home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-05-17 | 256.9 KB | 8,411 lines | [TEXT/MPS ] |
- /*
- File: PeleFWIM.c
-
- Contains: FireWire interface module software for Pele-based 1394 cards.
-
- Written by: Eric W. Anderson
-
- Copyright: © 1997 by Apple Computer, Inc., all rights reserved.
- FireWire is a registered trademark of Apple Computer, Inc.,
- in the United States and other countries.
- This file is Apple Confidential. Distribution is restricted.
-
- Change History (most recent first):
-
- <FW2> 6/5/97 EA Fill in contains and written by fields.
- <FW1> 6/5/97 EA first checked in
-
- */
-
- // This was adapted from LynxFWIM sample code and earlier Pele FWIM work.
- // Asynch is now spelled consistently to match Isoch, except where the Pele
- // spec says "async". (e.g. asyncRetryCnt)
-
- // Still need to clean up usage of Lynx terminology such as "PCL".
- // Substitute "DBDMA" or "Descriptor" when you see "PCL".
-
- // Major items not completed:
- // Honor IRDMA start-on-cycle requests (now we just start ASAP)
- // Honor SendPacketWithHeaderStartOp (returns error currently)
- // Find a way to make ReceivePacketOp work (returns error)
- // Make VM work in all cases (currently requires contiguous pages)
- // Make IRDMA safe if callProc/etc. happens in both channels before first packet.
- // Read serial (or other) EEPROM to learn globally unique ID (GUID)
- // Set contender bit correctly if we can
- // Sometimes the ITDMA gets stuck active. Stop more cleanly to avoid this. (not just run=0)
- // Fix cycleTooLong causing the cycle master state machine to jam on resets.
- // Would be nice to use the ATRetry hardware.
- // Should correctly process acks, and should not busy-wait for acks.
-
- // There are #defines below in the Driver Descriptor that select some vendor-
- // specific PCI identification codes. Be sure to make any needed changes.
- // If you're going to ship a product, call it something other than PeleFWIM.
- // For example, VendorFWIM or VendorPeleFWIM, where Vendor is your name.
- // All other vendor-specific options are located here:
-
-
- // Define this if your Pele is an older design that does not support
- // the phyRegRcvd interrupt (bit 30 in the various interrupt registers).
-
- //#define PELE_NO_PHY_REG_RCVD
-
-
- // Define this if your Pele IRDMA cannot perform startOnEvent 00 (ie, set run
- // bit to start). This will cause us to use event 11 instead (ie, pretend that
- // the condition was already satisfied), which seems to work on such Peles.
-
- //#define PELE_NO_START_ON_RUN
-
-
- // There are no #defines for LinkOnEnable and EnableAT, because using those
- // features on Peles that don't implement them seems to be harmless.
-
-
-
- // General Pele tips and notes
- //
- // Pele interrupts are edge-triggered. If you clear an interrupt without clearing the
- // condition that caused it, you may not get another interrupt. For example, cycleTooLong
- // will stay high until you turn the cycle master off and then back on, but if you clear
- // this interrupt without doing that, you won't get any more of them, even though the
- // cycle master state machine is still stuck.
- //
- // STORE_QUAD can take a byte or word, but it always writes 32 bits, zero-padded if needed.
- //
- // On some Peles, starting the IRDMA by setting startOnEvent to 3 may cause stopOnEvent to
- // also go to 3, thus stopping the IRDMA. Use the above #define only if you have to.
- //
- // As with any 1394 Link, you should avoid touching registers when possible. For example,
- // don't poll some register in a tight loop while waiting for DMA to finish. All of those
- // reads will slow down the DMA.
-
- #include <Types.h>
- #include <Errors.h>
- #include <Devices.h>
- #include <Interrupts.h>
- #include <PCI.h>
- #include <DriverServices.h>
- #include <FireWire.h>
- #include <PeleFWIM.h>
- /*zzz*/
- #include <stdio.h>
- char debugStr[256];
- pascal void FWDebugStr(
- ConstStr255Param debuggerMsg)
- {
- #ifdef FW_DEBUG_BUILD
- #if FW_DEBUG_BUILD
- DebugStr (debuggerMsg);
- #endif
- #endif
- }
- /*zzz*/
-
- // Define this to check for Logical != Physical (use with VM off)
- // Warning, not fully implemented in PeleFWIM (see LynxFWIM)
- //#define PeleVMDebug
-
- // Define this to enable sending diagnostic messages to FireBug
- // Warning, not fully implemented in PeleFWIM (see LynxFWIM)
- //#define PeleFireBug
-
- #ifdef PeleFireBug
- char fireBug[256];
- #endif
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Internal procedure prototypes.
- //
-
- static OSStatus PeleFWIMInitialize (
- FWIMInitializeParamsPtr pFWIMInitializeParams);
-
- static OSStatus PeleFWIMFinalize (
- FWIMFinalizeParamsPtr pFWIMFinalizeParams);
-
- static OSStatus PeleFWIMPollInterrupts (
- FWIMPollInterruptsParamsPtr pFWIMPollInterruptsParams);
-
- static OSStatus PeleFWIMGetRegisterBaseAddress (
- PeleFWIMDataPtr pPeleFWIMData);
-
- static OSStatus PeleFWIMInstallInterruptHandler (
- PeleFWIMDataPtr pPeleFWIMData);
-
- static UInt16 PeleFWIMcrc16(
- UInt32 *data,
- UInt32 count);
-
- static OSStatus PeleFWIMFullReset(
- PeleFWIMDataPtr pPeleFWIMData);
-
- static OSStatus PeleFWIMExceptionHandler (
- ExceptionInformationPowerPC *theException);
-
- static InterruptMemberNumber PeleFWIMInterruptHandler (
- InterruptSetMember interruptSet,
- void *interruptRefCon,
- UInt32 interruptCount);
-
- static OSStatus PeleFWIMDispatchInterrupts (
- PeleFWIMDataPtr pPeleFWIMData);
-
- static void PeleFWIMHandleDMAARInterrupt(
- PeleFWIMDataPtr pPeleFWIMData);
-
- static void PeleFWIMHandleDMAIRAInterrupt(
- PeleFWIMDataPtr pPeleFWIMData);
-
- static void PeleFWIMHandleDMAITAInterrupt(
- PeleFWIMDataPtr pPeleFWIMData);
-
- static void PeleFWIMHandleResetInterrupt (
- PeleFWIMDataPtr pPeleFWIMData);
-
- #ifndef PELE_NO_PHY_REG_RCVD
- static void PeleFWIMHandlePhyRegRcvdInterrupt (
- PeleFWIMDataPtr pPeleFWIMData);
- #endif
-
- static void PeleFWIMHandleMiscInterrupt(
- PeleFWIMDataPtr pPeleFWIMData);
-
- static OSStatus PeleFWIMResetBus (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMSetContenderBit (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMClearContenderBit (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMEnableCycleMaster (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMDisableCycleMaster (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMSetRootHoldoffBit (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMClearRootHoldoffBit (
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMGetUniqueID (
- FWIMGetUniqueIDParamsPtr pFWIMGetUniqueIDParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMSendLinkOnPacket (
- FWIMSendPhyPacketParamsPtr pFWIMSendPhyPacketParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMSendPhyConfigurationPacket (
- FWIMSendPhyPacketParamsPtr pFWIMSendPhyPacketParams,
- UInt32 *pCommandAcceptance);
-
- static void PeleFWIMWritePhyRegister (
- PeleRegistersPtr pLinkRegs,
- UInt8 regAddress,
- UInt8 regData);
-
- static UInt8 PeleFWIMReadPhyRegister (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleRegistersPtr pLinkRegs,
- UInt8 regAddress);
-
- static void PeleFWIMAddAsynchRxDMA (
- PeleAsynchRxDMADataPtr pPeleAsynchRxDMAData);
-
- static void PeleFWIMCreateAsynchRxDMAProgram (
- PeleFWIMDataPtr pPeleFWIMData);
-
- static void PeleFWIMCreateAsynchRxOverflowDMASegment (
- PeleFWIMDataPtr pPeleFWIMData);
-
- static void PeleFWIMStartAsynchRxDMAProgram (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pPeleAsynchRxDMAData);
-
- static void PeleFWIMAddAsynchTxDMA (
- PeleAsynchTxDMADataPtr pTxDMAData);
-
- static void PeleFWIMCreateAsynchTxDoneDMASegment (
- PeleFWIMDataPtr pPeleFWIMData);
-
- static void PeleFWIMCreateAsynchTxDataDMA (
- PeleFWIMDataPtr pPeleFWIMData);
-
- static void PeleFWIMStartAsynchTxDMAProgram (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchTxDMADataPtr pStartTxDMAData);
-
- static OSStatus PeleFWIMWriteAT(
- PeleFWIMDataPtr pPeleFWIMData,
- UInt32 speed,
- UInt32 baseCount,
- UInt32 data1,
- UInt32 data2,
- UInt32 data3,
- UInt32 data4,
- UInt32 extCount,
- UInt32 *extData);
-
- static OSStatus PeleFWIMBuildAsynchTxDMA (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchTxDMADataPtr pTxDMAData,
- IOPreparationID *pIOPreparationID,
- Ptr buffer1,
- UInt32 size1,
- Ptr buffer2,
- UInt32 size2);
-
- static OSStatus PeleFWIMRead (
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMReadResponse (
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMWriteTimer (
- void *p1,
- void *p2);
-
- static OSStatus PeleFWIMWrite (
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMWriteResponse (
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMLock (
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMLockResponse (
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance);
-
- static Boolean PeleFWIMIsCompilableDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus PeleFWIMCompileDCLProgram (
- PeleFWIMDataPtr pPeleFWIMData,
- DCLProgramID dclProgramID,
- UInt32 dmaChannelNum,
- UInt32 channelNum,
- UInt32 speed);
-
- static OSStatus PeleFWIMAddDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddReceivePacketStartDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddReceivePacketDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddSendPacketStartDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddSendPacketWithHeaderStartDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddSendPacketDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddCallProcDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddJumpDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddUpdateDCLListDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddTimeStampDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddStopDCL(
- PeleDMABuildStatePtr pPeleDMABuildState);
-
- static OSStatus PeleFWIMDMAStart (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleDMABuildStatePtr *ppPeleDMABuildState,
- PeleDMAPtr *ppStartDMA);
-
- static OSStatus PeleFWIMAddLabelDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMAddSetTagSyncBitsDCL (
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMResolveDCLLabel (
- DCLLabelPtr pDCLLabel);
-
- static OSStatus PeleFWIMDCLCompilerNotification (
- DCLProgramID dclProgramID,
- UInt32 notificationType,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus PeleFWIMDCLCompilerUpdateNotification (
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus PeleFWIMUpdateDCLTimeStamp (
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMUpdateDCLReceivePacketStart (
- DCLCommandPtr pDCLCommand);
-
- static OSStatus PeleFWIMDCLCompilerModifyNotification (
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands);
-
- static OSStatus PeleFWIMAllocateDMABuildState (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleDMABuildStatePtr *ppPeleDMABuildState);
-
- static OSStatus PeleFWIMAllocateDMA (
- PeleDMABuildStatePtr pPeleDMABuildState,
- PeleDMAPtr *ppDMA,
- PhysicalAddress *ppDMAPhys,
- UInt32 count);
-
- static void PeleFWIMDeallocateDMAPools (
- PeleDMAPoolDataPtr pPeleDMAPoolDataList);
-
- static void PeleFWIMRunDCLProgram (
- PeleIsochPortDataPtr pPeleIsochPortData,
- Ptr packetBuffer,
- UInt32 packetSize,
- DCLCommandPtr *ppDCLCommand);
-
- static void PeleFWIMDCLReceivePacketStart (
- Ptr *pPacketBuffer,
- UInt32 *pPacketSize,
- DCLCommandPtr *ppDCLCommand,
- Boolean *pWaitForPacket);
-
- static void PeleFWIMDCLReceiveBuffer (
- Ptr *pPacketBuffer,
- UInt32 *pPacketSize,
- DCLCommandPtr *ppDCLCommand,
- Boolean *pWaitForPacket);
-
- static OSStatus PeleFWIMAllocateIsochPort (
- FWIMAllocateIsochPortParamsPtr
- pFWIMAllocateIsochPortParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMReleaseIsochPort (
- FWIMReleaseIsochPortParamsPtr
- pFWIMReleaseIsochPortParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus _PeleFWIMReleaseIsochPort (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleIsochPortDataPtr pPeleIsochPortData);
-
- static OSStatus PeleFWIMStartIsochPort (
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMStopIsochPort (
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance);
-
- static OSStatus PeleFWIMStartTalkingDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus PeleFWIMStartListeningDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus PeleFWIMStopTalkingDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus PeleFWIMStopListeningDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus PeleFWIMReleaseDCLProgram (
- DCLProgramID dclProgramID);
-
- static OSStatus PeleFWIMReadRequestTimeoutHandler (
- void *p1,
- void *p2);
-
- static OSStatus PeleFWIMWriteRequestTimeoutHandler (
- void *p1,
- void *p2);
-
- static OSStatus PeleFWIMLockRequestTimeoutHandler (
- void *p1,
- void *p2);
-
- static void PeleFWIMDMAARDeferredTask(
- void *p1,
- void *p2);
-
- static void PeleFWIMDMAIsochReceiveDeferredTask(
- void *p1,
- void *p2);
-
- static void PeleFWIMDMAIsochTransmitDeferredTask(
- void *p1,
- void *p2);
-
- static void PeleFWIMResetDeferredTask (
- void *p1,
- void *p2);
-
- static OSStatus PeleFWIMDelayedReset(
- void *p1,
- void *p2);
-
- static void PeleFWIMMiscInterruptDeferredTask (
- void *p1,
- void *p2);
-
- static OSStatus PeleFWIMAckSecondaryInterruptHandler (
- void *p1,
- void *p2);
-
- static void PeleFWIMProcessPacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessSelfIDPacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessWriteQuadletPacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessWriteQuadletRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void PeleFWIMProcessWriteBlockPacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessWriteBlockRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void PeleFWIMProcessWriteResponsePacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessReadQuadletPacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessReadQuadletRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void PeleFWIMProcessReadBlockPacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessReadBlockRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void PeleFWIMProcessReadQuadletResponsePacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessReadBlockResponsePacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessLockPacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- static void PeleFWIMProcessLockRequestCompletionProc (
- FWIMProcessParamsPtr pFWIMProcessParams);
-
- static void PeleFWIMProcessLockResponsePacket (
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize);
-
- #ifdef PeleFireBug
- static void PeleFWIMFireBugMsg (
- PeleFWIMDataPtr pPeleFWIMData,
- char *msg);
- #endif
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // The driver descriptor.
- //
-
- // Define one of these or edit the driver descriptor as needed.
- // These are not used elsewhere in the code, except for PELE_VENDOR_NONE
- // which will cause a compiler warning (see below).
-
- //#define PELE_VENDOR_A
- //#define PELE_VENDOR_F
- //#define PELE_VENDOR_S1
- //#define PELE_VENDOR_S2
- #define PELE_VENDOR_NONE
-
-
- DriverDescription TheDriverDescription =
- {
- kTheDescriptionSignature,
- kInitialDriverDescriptor,
- {
- #ifdef PELE_VENDOR_A
- "\ppci9004,8940",
- #endif
- #ifdef PELE_VENDOR_F
- "\ppci12bf,0",
- #endif
- #ifdef PELE_VENDOR_S1
- "\ppci1000,301",
- #endif
- #ifdef PELE_VENDOR_S2
- "\ppci104d,8009",
- #endif
- #ifdef PELE_VENDOR_NONE
- "\ppciNULL,VOID",
- #endif
- 1, 0, finalStage, 1,
- },
- {
- kDriverIsUnderExpertControl,
- "\pPeleFWIM", // RENAME THIS - see preamble comments
- },
-
- 1,
- kServiceCategoryFWIM,
- 0,
- 1,0,0,0
- };
-
-
- // This hack will cause the compiler to warn about an unused variable or
- // an uninitialized variable (or both), at least in the MPW environment
- // used by Apple. You are supposed to get a clue from this that you need
- // to define the PCI name in the Driver Descriptor (above).
-
- #ifdef PELE_VENDOR_NONE
- static UInt32 PeleFWIM_Compiler_warning_hack ()
- {
- UInt32 WARNING___NO_PELE_VENDOR_DEFINED;
- UInt32 _WARNING___NO_PELE_VENDOR_DEFINED;
- return _WARNING___NO_PELE_VENDOR_DEFINED;
- }
- #endif
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // The plug in dispatch table.
- //
-
- FWIMPluginDispatchTable ThePluginDispatchTable =
- {
- kFWIMPluginVersion,
- PeleFWIMInitialize,
- PeleFWIMFinalize,
- PeleFWIMPollInterrupts,
- PeleFWIMSendLinkOnPacket,
- PeleFWIMSendPhyConfigurationPacket,
- PeleFWIMRead,
- PeleFWIMReadResponse,
- PeleFWIMWrite,
- PeleFWIMWriteResponse,
- PeleFWIMLock,
- PeleFWIMLockResponse,
- PeleFWIMAllocateIsochPort,
- PeleFWIMReleaseIsochPort,
- PeleFWIMStartIsochPort,
- PeleFWIMStopIsochPort,
- PeleFWIMResetBus,
- PeleFWIMSetContenderBit,
- PeleFWIMClearContenderBit,
- PeleFWIMEnableCycleMaster,
- PeleFWIMDisableCycleMaster,
- PeleFWIMSetRootHoldoffBit,
- PeleFWIMClearRootHoldoffBit,
- PeleFWIMGetUniqueID
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMInitialize
- //
- // This is the FWIM installer proc. It allocates the FWIM data record, gets
- // the register base address, installs the interrupt handler, enables the
- // register memory space, sets the chip up to receive selfID packets,
- // enables bus reset interrupts, and initiates a bus reset to get the topology
- // map.
- //zzz Clean up on error???
- //zzz Do we always need to initiate a bus reset???
- //
-
- static OSStatus PeleFWIMInitialize(
- FWIMInitializeParamsPtr pFWIMInitializeParams)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- RegEntryIDPtr pFWIMRegEntryID;
- Ptr p;
- IOPreparationTable *ioPrep;
- UInt32 pageSize, totalAlloc;
- UInt32 bufsPerPage, bufPages;
- UInt32 dmasPerPage, dmaPages;
- UInt32 doBuf, doPage, bufsDone, offset;
- Ptr logPage, physPage;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMInitialize");
-
- pageSize = GetLogicalPageSize ();
-
- // Allocate Pele FWIM data.
- // Parts of this struct will be phyiscally addressed, so we need
- // to make sure those parts don't straddle a page boundary. To
- // guarantee this, we put them first in the struct, and we'll
- // page-align the whole struct, and map the first page.
-
- // Phys addressing may be moot with Pele. It was required in Lynx.
-
- p = PoolAllocateResident (sizeof (PeleFWIMData) + pageSize, true);
- if (p)
- {
- p = (Ptr) (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1)); // page-align
- pPeleFWIMData = (PeleFWIMDataPtr) p;
-
- pPeleFWIMData->pageSize = pageSize;
- pPeleFWIMData->pageShift = 1;
- while (pageSize >>= 1)
- pPeleFWIMData->pageShift++;
- pageSize = pPeleFWIMData->pageSize;
-
- ioPrep = &pPeleFWIMData->fwimDataIOPrep;
- ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = 1; // # of pages we will use
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = &pPeleFWIMData->fwimDataPhys; // return phys addr
- ioPrep->rangeInfo.range.base = (void *) pPeleFWIMData; // first addr to map
- ioPrep->rangeInfo.range.length = pageSize; // map one page
-
- // there is no CheckpointIO which matches this. It will be held down forever.
- status = PrepareMemoryForIO (ioPrep);
- if (status != noErr)
- {
- sprintf (debugStr, "FWIMData PrepMemIO status %ld logical %08lx physical %08lx len %lx",
- (long) status,
- (long) ioPrep->rangeInfo.range.base,
- (long) pPeleFWIMData->fwimDataPhys,
- (long) ioPrep->rangeInfo.range.length);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
-
- if (status == noErr)
- {
- pFWIMInitializeParams->fwimSpecificData = (UInt32) pPeleFWIMData;
- }
-
- }
- else
- {
- status = memFullErr;
- }
-
- // Get notification proc and name registry ID.
- if (status == noErr)
- {
- pPeleFWIMData->fwimID = pFWIMInitializeParams->fwimID;
- pPeleFWIMData->FWIMRegEntryID = pFWIMInitializeParams->fwimRegEntryID;
- pFWIMRegEntryID = &(pPeleFWIMData->FWIMRegEntryID);
- }
-
- // Get register base address.
- if (status == noErr)
- {
- status = PeleFWIMGetRegisterBaseAddress (pPeleFWIMData);
- }
-
- // Note - sometimes these buffers are used to assemble response packets
- // So even if only a few quads are used in receiving, the rest of the buffer
- // may still be written to later (see PeleFWIMProcessReadBlockPacket, etc.)
-
- // Allocate asynch / self-ID buffers:
- // Buffers will not span page boundaries (for now, max rcv packet fits in a page)
- // and will be 32-byte aligned for best Pele performance. To save memory, alloc
- // one big buffer, prep it for I/O, and carve it up. If marked for input, we can
- // re-use it over and over with no VM upkeep. kAsyncRxPacketBufferSize must be multiple of 32.
- // PCLs are PCL-size-aligned, PCL-size is 128 and must divide the page size (easy).
-
- // Use a single allocation for asynch xmit/rcv buffers and xmit/rcv PCLs. Marking
- // all the memory as "input | output" may prevent some optimizations - future feature.
-
- // Note, because we don't span page boundaries, we don't need to request contig
- // memory. Change to ordinary allocate once it's working. (Asynch rcv PCLs do span
- // pages, fix that first)
-
- if (status == noErr)
- {
- bufsPerPage = pageSize / kAsyncRxPacketBufferSize;
- bufPages = (kAsynchRxBufs + bufsPerPage - 1) / bufsPerPage;
- dmasPerPage = pageSize / sizeof (PeleDMA);
- dmaPages = (kAsynchRxBufs + dmasPerPage - 1) / dmasPerPage;
-
- totalAlloc = bufPages; // Space for asynch rcv bufs
- totalAlloc += 1; // Space for asynch xmit buf
- totalAlloc += dmaPages; // Space for asynch rcv PCLs
- totalAlloc += 1; // Space for asynch xmit PCLs
- totalAlloc += 1; // Round up to page boundary
-
- // Use PoolAllocate to get a page table - don't use the stack.
-
- p = MemAllocatePhysicallyContiguous (totalAlloc * pageSize, false);
-
- if (!p)
- {
- status = memFullErr;
- sprintf (debugStr, "Asynch buf/PCL alloc failure, asked for %ld",
- (long) totalAlloc * pageSize);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
-
- if (status == noErr)
- {
- // I think MemAllocatePhysicallyContiguous gives us memory starting
- // on a page boundary. But just in case, align ourselves:
-
- sprintf (debugStr, "Allocated phys memory at %08lx", (long) p);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- p = (Ptr) ((((UInt32) p) + (pageSize - 1)) & ~(pageSize - 1)); // page-align
-
- sprintf (debugStr, " Aligned to %08lx", (long) p);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- // Mark this memory for Input, and learn the physical address
- ioPrep = &pPeleFWIMData->ioPrep;
- ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = totalAlloc; // # of pages we will use
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = pPeleFWIMData->physAddrs; // return list of phys addrs
- ioPrep->rangeInfo.range.base = (void *) p;
- ioPrep->rangeInfo.range.length = totalAlloc * pageSize;
-
- // There is no CheckpointIO which matches this. The buffers are ours for keeps.
- status = PrepareMemoryForIO (ioPrep);
- if (status != noErr)
- {
- sprintf (debugStr, "PrepMemIO status %ld logical %08lx physical %08lx len %lx",
- (long) status,
- (long) ioPrep->rangeInfo.range.base,
- (long) pPeleFWIMData->physAddrs[0],
- (long) ioPrep->rangeInfo.range.length);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- }
-
- // Carve up what we got and store away the addrs
- if (status == noErr)
- {
- // Asynch rcv buffers (kAsykcBufs)
-
- bufsDone = 0;
- for (doBuf = 0; doBuf < bufPages; doBuf++)
- {
- logPage = p + (doBuf * pageSize);
- physPage = (Ptr) pPeleFWIMData->physAddrs[doBuf];
-
- for (doPage = 0; doPage < bufsPerPage; doPage++)
- {
- if (bufsDone < kAsynchRxBufs)
- {
- offset = doPage * kAsyncRxPacketBufferSize;
- pPeleFWIMData->asynchBuf[bufsDone] = logPage + offset;
- pPeleFWIMData->asynchBufPhys[bufsDone] = physPage + offset;
-
- bufsDone++;
- }
- }
- }
- sprintf (debugStr, "Asynch bufs ready, log base %08lx, phys base %08lx, count %lx",
- (long) pPeleFWIMData->asynchBuf,
- (long) pPeleFWIMData->asynchBufPhys,
- (long) kAsynchRxBufs);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- // Asynch xmit buffer (1)
-
- p += (bufPages * pageSize);
- pPeleFWIMData->asynchXmitBuf = p;
- pPeleFWIMData->asynchXmitBufPhys = pPeleFWIMData->physAddrs[bufPages];
-
- // Asynch rcv DMAs (kAsykcBufs)
- // WARNING rcv code assumes all DMAs are contiguous.
- // If made non-contig, will have to change several places
-
- p += pageSize;
- pPeleFWIMData->asynchDMA = (PeleDMA *) p;
- pPeleFWIMData->asynchDMAPhys = pPeleFWIMData->physAddrs[bufPages + 1];
-
- // Asynch xmit dbdma (16) //zzz sloppy but should be OK
-
- p += (dmaPages * pageSize);
- pPeleFWIMData->asynchXmitDMA = (PeleDMA *) p;
- pPeleFWIMData->asynchXmitDMAPhys = pPeleFWIMData->physAddrs[bufPages + 1 + dmaPages];
- }
- }
-
- // Allocate asynch receive PCL data records.
- if (status == noErr)
- {
- p = PoolAllocateResident (sizeof (PeleAsynchRxDMAData) * kAsynchRxBufs, true);
-
- if (p)
- pPeleFWIMData->asynchRxDMADataList = (PeleAsynchRxDMADataPtr) p;
- else
- status = memFullErr;
- }
-
- // Allocate asynch transmit data records.
- // This is actually too many
- if (status == noErr)
- {
- p = PoolAllocateResident (sizeof (PeleAsynchTxDMAData) * kNumAsynchTxDMAs, true);
-
- if (p)
- pPeleFWIMData->AsynchTxDMADataList = (PeleAsynchTxDMADataPtr) p;
- else
- status = memFullErr;
- }
-
- // Set up asynch transmit PCLs.
- if (status == noErr)
- {
- PeleFWIMCreateAsynchTxDoneDMASegment (pPeleFWIMData);
- PeleFWIMCreateAsynchTxDataDMA (pPeleFWIMData);
- }
-
- // Create deferred task for handling bus resets.
- if (status == noErr)
- {
- status = FWCreateDeferredTask (&(pPeleFWIMData->busResetDeferredTaskID),
- PeleFWIMResetDeferredTask,
- pPeleFWIMData);
- }
-
- // Create deferred task for handling received asynch packets.
- if (status == noErr)
- {
- status = FWCreateDeferredTask (&(pPeleFWIMData->asynchReceiveDeferredTaskID),
- PeleFWIMDMAARDeferredTask,
- pPeleFWIMData);
- }
-
- // Create deferred task for handling received isoch packets.
- if (status == noErr)
- {
- status = FWCreateDeferredTask (&(pPeleFWIMData->isochReceiveDeferredTaskID),
- PeleFWIMDMAIsochReceiveDeferredTask,
- pPeleFWIMData);
- }
-
- // Create deferred task for handling transmitted isoch packets.
- if (status == noErr)
- {
- status = FWCreateDeferredTask (&(pPeleFWIMData->isochTransmitDeferredTaskID),
- PeleFWIMDMAIsochTransmitDeferredTask,
- pPeleFWIMData);
- }
-
- // Create deferred task for handling miscellaneous interrupts.
- if (status == noErr)
- {
- status = FWCreateDeferredTask (&(pPeleFWIMData->miscInterruptDeferredTaskID),
- PeleFWIMMiscInterruptDeferredTask,
- pPeleFWIMData);
- }
-
- // Install interrupt handler.
- if (status == noErr)
- {
- status = PeleFWIMInstallInterruptHandler (pPeleFWIMData);
- }
-
- // Use config space to enable bus mastering and memory space.
- if (status == noErr)
- {
- status = ExpMgrConfigWriteWord (
- pFWIMRegEntryID, (LogicalAddress) cwCommand,
- (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
- }
-
- // FWDebugStr ((ConstStr255Param) "\p PeleFWIMInitialize: Start poking registers");
-
- if (status == noErr) status = PeleFWIMFullReset (pPeleFWIMData);
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMInitialize: Done!");
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMFinalize
- //
- // This is the FWIM finalizing proc. It deallocates everything.
- // I believe this isn't actually used (yet).
- //
-
- static OSStatus PeleFWIMFinalize(
- FWIMFinalizeParamsPtr pFWIMFinalizeParams)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMFinalizeParams->fwimSpecificData;
-
- //zzz deallocate everything.
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMPollInterrupts
- //
- // This proc checks for pending interrupts.
- // I believe this isn't actually used (yet), but it might apply if we needed
- // to process interrupts while they were disabled (say, if Pele was part of
- // the connection to our backing store).
- //
-
- static OSStatus PeleFWIMPollInterrupts(
- FWIMPollInterruptsParamsPtr pFWIMPollInterruptsParams)
- {
- OSStatus status = noErr;
-
- status = PeleFWIMDispatchInterrupts
- ((PeleFWIMDataPtr) pFWIMPollInterruptsParams->fwimSpecificData);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMGetRegisterBaseAddress
- //
- // This proc uses the name registry to find the base address of the registers.
- //
-
- static OSStatus PeleFWIMGetRegisterBaseAddress(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- RegEntryIDPtr pFWIMRegEntryID = &(pPeleFWIMData->FWIMRegEntryID);
- PCIAssignedAddressPtr tempFWIMAddressesStorage = nil,
- pFWIMAddresses;
- Ptr pFWIMAddressesEnd;
- DeviceLogicalAddressPtr tempFWIMLogicalAddressesStorage = nil,
- pFWIMLogicalAddresses;
- RegPropertyValueSize propSize;
- UInt32 assignedAddressesSize;
- Boolean done;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMGetRegisterBaseAddress");
-
- // Get assigned addresses property.
- status = RegistryPropertyGetSize
- (pFWIMRegEntryID,
- (RegPropertyNamePtr) kPCIAssignedAddressProperty,
- &propSize);
-
- if (status == noErr)
- {
- tempFWIMAddressesStorage =
- (PCIAssignedAddressPtr) PoolAllocateResident (propSize, false);
- if (tempFWIMAddressesStorage == nil)
- status = memFullErr;
- else
- pFWIMAddresses = tempFWIMAddressesStorage;
- }
-
- if (status == noErr)
- {
- status = RegistryPropertyGet
- (pFWIMRegEntryID,
- (RegPropertyNamePtr) kPCIAssignedAddressProperty,
- pFWIMAddresses,
- &propSize);
- assignedAddressesSize = propSize;
- }
-
- // Get logical addresses property.
- if (status == noErr)
- {
- status = RegistryPropertyGetSize
- (pFWIMRegEntryID,
- (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
- &propSize);
- }
-
- if (status == noErr)
- {
- tempFWIMLogicalAddressesStorage =
- (DeviceLogicalAddressPtr) PoolAllocateResident (propSize, false);
- if (tempFWIMLogicalAddressesStorage == nil)
- status = memFullErr;
- else
- pFWIMLogicalAddresses = tempFWIMLogicalAddressesStorage;
- }
-
- if (status == noErr)
- {
- status = RegistryPropertyGet
- (pFWIMRegEntryID,
- (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
- pFWIMLogicalAddresses,
- &propSize);
- }
-
- // Scan addresses until we find the one at config space 0x10.
- if (status == noErr)
- {
- pFWIMAddressesEnd = ((Ptr) pFWIMAddresses) + assignedAddressesSize;
- done = false;
-
- while ((((Ptr) pFWIMAddresses) < pFWIMAddressesEnd) && (!done))
- {
- if (pFWIMAddresses->registerNumber == 0x10)
- {
- // There is a certain prototype system in which Open Firmware
- // doesn't seem to work quite right yet. If we find that the
- // base register is zero, substitute another value for now.
-
- if (!*pFWIMLogicalAddresses)
- {
- pPeleFWIMData->pPeleRegisters = (PeleRegistersPtr) pFWIMAddresses->address.lo;
-
- sprintf (debugStr, "Base register 0, using %08lx", (long) pFWIMAddresses->address.lo);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- else
- {
- pPeleFWIMData->pPeleRegisters = (PeleRegistersPtr) *pFWIMLogicalAddresses;
- }
- done = true;
- }
-
- pFWIMAddresses++;
- pFWIMLogicalAddresses++;
- }
-
- if (!done)
- status = paramErr;
- }
-
- // Deallocate temp storage.
- if (tempFWIMAddressesStorage != nil)
- PoolDeallocate ((LogicalAddress) tempFWIMAddressesStorage);
-
- if (tempFWIMLogicalAddressesStorage != nil)
- PoolDeallocate ((LogicalAddress) tempFWIMLogicalAddressesStorage);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMInstallInterruptHandler
- //
- // This proc installs the chip interrupt handler.
- //
-
- static OSStatus PeleFWIMInstallInterruptHandler(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- RegEntryIDPtr pFWIMRegEntryID = &(pPeleFWIMData->FWIMRegEntryID);
- ISTProperty interruptSets;
- InterruptSetID interruptSetID;
- InterruptMemberNumber interruptMemberNumber;
- void *oldInterruptRefCon;
- InterruptHandler oldInterruptHandler;
- InterruptEnabler interruptEnabler;
- InterruptDisabler interruptDisabler;
- RegPropertyValueSize propSize;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMInstallInterruptHandler");
-
- // Get our interrupt set from the name registry.
- propSize = sizeof (ISTProperty);
- status = RegistryPropertyGet (pFWIMRegEntryID, kISTPropertyName,
- &interruptSets, &propSize);
- interruptSetID = interruptSets[kISTChipInterruptSource].setID;
- interruptMemberNumber = interruptSets[kISTChipInterruptSource].member;
-
- // Get the interrupt enabler and disabler for our chip interrupt set.
- if (status == noErr)
- {
- status = GetInterruptFunctions
- (interruptSetID, interruptMemberNumber,
- &oldInterruptRefCon, &oldInterruptHandler,
- &interruptEnabler, &interruptDisabler);
- }
-
- // Install the refCon and interrupt handler for our chip interrupt set.
- if (status == noErr)
- {
- status = InstallInterruptFunctions
- (interruptSetID, interruptMemberNumber,
- pPeleFWIMData, (InterruptHandler) PeleFWIMInterruptHandler,
- nil, nil);
- }
-
- // Add info to our FWIM Data record.
- if (status == noErr)
- {
- pPeleFWIMData->interruptSetMember.setID = interruptSetID;
- pPeleFWIMData->interruptSetMember.member = interruptMemberNumber;
- pPeleFWIMData->oldInterruptRefCon = oldInterruptRefCon;
- pPeleFWIMData->oldInterruptHandler = oldInterruptHandler;
- pPeleFWIMData->interruptEnabler = interruptEnabler;
- pPeleFWIMData->interruptDisabler = interruptDisabler;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMcrc16
- //
- // Compute the CRC-16 value of a block of quadlets.
- // Adapted from Table 23 of IEEE 1212.
- // Takes quadlet pointer and count of quadlets
-
- static UInt16 PeleFWIMcrc16(
- UInt32 *data,
- UInt32 count)
- {
- SInt32 shift;
- UInt16 sum, next = 0;
- UInt32 doCount = count, *doData = data;
-
- while (doCount--)
- {
- for (shift = 28; shift >= 0; shift -= 4) // 8 times, 4 bits each time
- {
- sum = ((next >> 12) ^ (*doData >> shift)) & 0x0f; // get 4 bits
- next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; // apply them
- }
- doData++;
- }
-
- return next;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMFullReset
- //
-
- static OSStatus PeleFWIMFullReset(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- PeleRegistersPtr pPeleRegs;
- UInt32 interruptMask;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\p(Pele) PeleFWIMFullReset");
-
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Reset everything possible
- pPeleRegs->reset =
- EndianSwapImm32Bit (kPeleResetReceiver |
- kPeleResetTransmitter |
- kPeleResetRF |
- kPeleResetITF |
- kPeleResetATF);
- SynchronizeIO ();
-
- // Note, some older Pele parts don't have the LinkOnEnable bit.
- // Setting it should be harmless (and useless) on those parts.
-
- // Clear resets and turn on link
- pPeleRegs->reset = EndianSwapImm32Bit (kPeleResetLinkOnEnable);
- SynchronizeIO ();
-
- // Create the asynch receive program.
- PeleFWIMCreateAsynchRxDMAProgram (pPeleFWIMData);
-
- // Start asynch receive program.
- PeleFWIMStartAsynchRxDMAProgram
- (pPeleFWIMData, &(pPeleFWIMData->asynchRxDMADataList[kAsynchRxFirstPacketDMA]));
-
- // Could set hardware retry counter here (?)
-
- // Enable Receiver and Transmitter, disable physical DMA
- pPeleRegs->control =
- EndianSwapImm32Bit ((kPelePhysDMAnoAccess << kPeleControlPhysDMAEnablePhase) |
- kPeleControlReceiveEnable |
- kPeleControlTransmitEnable);
- SynchronizeIO ();
- pPeleRegs->packetControl = EndianSwapImm32Bit (kPelePacketControlRcvSelfID);
- SynchronizeIO ();
-
- // Set our bus number to default 0x3FF.
- //zzz If 1394.1 is ever finished, we'll need to know how to learn the real number
- // Pele's node number register is read-only, so we can just OR in the 0x3FF:
- pPeleRegs->nodeID |= EndianSwapImm32Bit (0x3FF << kPeleNodeIDBusNumberPhase);
- SynchronizeIO ();
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMFullReset: Enable interrupts");
-
- // Enable chip interrupts.
- if (status == noErr)
- {
- (*(pPeleFWIMData->interruptEnabler)) (pPeleFWIMData->interruptSetMember,
- pPeleFWIMData->oldInterruptRefCon);
- }
-
- // Enable interrupts for bus resets, phy registers, and DMA ints
- {
- interruptMask = kPeleIntBusReset |
- kPeleIntDMAAR |
- kPeleIntDMAIRA |
- kPeleIntDMAIRB |
- kPeleIntDMAITA;
-
- #ifndef PELE_NO_PHY_REG_RCVD
- interruptMask |= kPeleIntPhyRegRcvd;
- #endif
-
- pPeleRegs->interruptMask = EndianSwap32Bit (interruptMask);
- SynchronizeIO ();
-
- // Enable additional interrupts only if we are running FireBug.
- // Interrupts will be reported to FireBug.
- // Normally there's nothing we can do about these interrupts.
-
- #ifdef PeleFireBug
- pPeleRegs->interruptMask |=
- EndianSwapImm32Bit (kPeleIntHdrErr);
- SynchronizeIO ();
- #endif
-
- }
-
- // Enable Cycle Timer.
- pPeleRegs->control |= EndianSwapImm32Bit (kPeleControlCycleTimerEnable);
- SynchronizeIO ();
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMFullReset: Survived!");
-
- return noErr; // at no point did we check any status
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMExceptionHandler
- //
- // This proc handles exceptions.
- // I believe that this never happens (yet).
- //
-
- static OSStatus PeleFWIMExceptionHandler(
- ExceptionInformationPowerPC *theException)
- {
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMExceptionHandler");
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMInterruptHandler
- //
- // This is the handler proc for chip interrupts.
- //
-
- static InterruptMemberNumber PeleFWIMInterruptHandler(
- InterruptSetMember interruptSetMember,
- void *interruptRefCon,
- UInt32 interruptCount)
- {
- PeleFWIMDispatchInterrupts ((PeleFWIMDataPtr) interruptRefCon);
-
- return kIsrIsComplete;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDispatchInterrupts
- //
- // This proc dispatches any pending interrupts.
- //
-
- static OSStatus PeleFWIMDispatchInterrupts(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- PeleRegistersPtr pPeleRegs;
- UInt32 interruptEvents, interruptEventsLittleEndian;
- OSStatus status = noErr;
-
- // Get our register base address.
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Read PCI interrupt status register.
- interruptEventsLittleEndian = pPeleRegs->interruptEvents;
- interruptEvents = EndianSwap32Bit (interruptEventsLittleEndian);
-
- // Note - there are lots of kinds of ints other than 1394 and DMA
- // that can happen. We'll probably want to catch some of them.
-
- // Check for bus reset, must do that first
- if (interruptEvents & kPeleIntBusReset)
- PeleFWIMHandleResetInterrupt (pPeleFWIMData);
-
- #ifndef PELE_NO_PHY_REG_RCVD
- // Check for PHY register received
- if (interruptEvents & kPeleIntPhyRegRcvd)
- PeleFWIMHandlePhyRegRcvdInterrupt (pPeleFWIMData);
- #endif
-
- // Check for DMA interrupts:
-
- if (interruptEvents & kPeleIntDMAAR)
- PeleFWIMHandleDMAARInterrupt (pPeleFWIMData);
-
- if (interruptEvents & kPeleIntDMAIRA)
- PeleFWIMHandleDMAIRAInterrupt (pPeleFWIMData);
-
- // Same handler as IRA:
- if (interruptEvents & kPeleIntDMAIRB)
- PeleFWIMHandleDMAIRAInterrupt (pPeleFWIMData);
-
- if (interruptEvents & kPeleIntDMAITA)
- PeleFWIMHandleDMAITAInterrupt (pPeleFWIMData);
-
- #ifdef PeleFireBug
- if (!(interrupt & kPelePHY_BUSRESET))
- {
- //PeleFWIMHandleMiscInterrupt (pPeleFWIMData);
- }
- #endif
-
- // Clear the interrupts.
- pPeleRegs->interruptClear = interruptEventsLittleEndian;
- SynchronizeIO ();
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMHandleDMAARInterrupt
- //
- // This proc handles asynch receive DMA interrupts.
- //
-
- static void PeleFWIMHandleDMAARInterrupt(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- OSStatus status = noErr;
-
- if (!(pPeleFWIMData->asynchReceiveDTScheduled))
- {
- status = FWScheduleDeferredTask (pPeleFWIMData->asynchReceiveDeferredTaskID, nil);
-
- if (status == noErr)
- pPeleFWIMData->asynchReceiveDTScheduled = true;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMHandleDMAIRAInterrupt
- //
- // This proc handles isoch receive A DMA interrupts.
- //
-
- static void PeleFWIMHandleDMAIRAInterrupt(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- OSStatus status = noErr;
-
- if (!(pPeleFWIMData->isochReceiveDTScheduled))
- {
- status = FWScheduleDeferredTask (pPeleFWIMData->isochReceiveDeferredTaskID, nil);
-
- if (status == noErr)
- pPeleFWIMData->isochReceiveDTScheduled = true;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMHandleDMAITAInterrupt
- //
- // This proc handles isoch transmit A DMA interrupts.
- //
-
- static void PeleFWIMHandleDMAITAInterrupt(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- OSStatus status = noErr;
-
- if (!(pPeleFWIMData->isochTransmitDTScheduled))
- {
- status = FWScheduleDeferredTask (pPeleFWIMData->isochTransmitDeferredTaskID, nil);
-
- if (status == noErr)
- pPeleFWIMData->isochTransmitDTScheduled = true;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMHandleResetInterrupt
- //
- // This proc handles bus reset interrupts.
- //zzz must be able to handle two resets happening before we process one.
- //
-
- static void PeleFWIMHandleResetInterrupt(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- PeleRegistersPtr pPeleRegs = pPeleFWIMData->pPeleRegisters;
- UInt32 control;
- OSStatus status = noErr;
-
- // Pele disables the asynch transmitter on bus resets. But, that disables
- // the sending of cycle-start packets if Pele is root. So, turn it back on.
- // Before we do that, ensure that the asynch transmit DMA is stopped.
-
- pPeleRegs->asynchTransmit.channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO();
-
- pPeleFWIMData->asynchTxDoneFlag = 0xFFFFFFFF;
-
- // I think there may be a hadrware bug in (some) Peles that will cause the
- // cycle master function to jam if it had already tried to send a cycle start
- // but found the transmitter disabled. To try to avoid this, first turn off
- // the cycle master, then enable the transmitter, then turn the cycle master
- // back on (only if it was already on). Soon after this, we'll get phy reg
- // 0 to tell us if we're still root or not - but for now, we don't know yet.
-
- control = pPeleRegs->control | EndianSwapImm32Bit (kPeleControlTransmitEnable);
- SynchronizeIO ();
- pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
- SynchronizeIO ();
- pPeleRegs->control = control;
- SynchronizeIO ();
-
- // Invalidate bus generation number.
- pPeleFWIMData->generationValid = false;
-
- // Process the reset.
- status = FWProcessBusReset (pPeleFWIMData->fwimID);
-
- // Schedule deferred task to handle reset.
- if (!(pPeleFWIMData->busResetDTScheduled))
- {
- status = FWScheduleDeferredTask (pPeleFWIMData->busResetDeferredTaskID, nil);
-
- if (status == noErr)
- pPeleFWIMData->busResetDTScheduled = true;
- }
-
- #ifdef PELE_NO_PHY_REG_RCVD
- // We're never going to get a PHY register received interrupt, so take care of this now:
- {
- AbsoluteTime absoluteDuration;
-
- // This should be enough time for the PHY to send register 0 to us.
-
- absoluteDuration = DurationToAbsolute (200 * durationMicrosecond);
- DelayForHardware (absoluteDuration);
-
- // It might be possible to poll for kPeleNodeIDValid rathen than delay 200 microseconds.
- // If that works, it is probably a better solution.
-
- if ((pPeleRegs->nodeID & kPeleNodeIDValid) && !(pPeleRegs->nodeID & kPeleNodeIDRoot))
- {
- if (pPeleRegs->control & EndianSwapImm32Bit (kPeleControlCycleMaster))
- {
- // See comments in PeleFWIMHandlePhyRegRcvdInterrupt.
-
- // Disable cycle mastering.
- pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
- SynchronizeIO ();
- }
- }
- }
- #endif
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMHandlePhyRegRcvdInterrupt
- //
- // This proc handles phy register receive interrupts.
- // Any time we get register 0, keep a copy.
- // Also keep a copy of the most recently received register.
- //
- // Some Pele-derived designs do not support this interrupt.
- //
-
- #ifndef PELE_NO_PHY_REG_RCVD
- static void PeleFWIMHandlePhyRegRcvdInterrupt(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
- UInt32 phyData;
-
- // This happens about 150 microseconds after a bus reset, when the PHY sends
- // register zero automatically. This also happens after we do a PHY read
- // in PeleFWIMReadPHYRegister.
-
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // NOTE This register read will clear the RdDone bit if it is set.
-
- pPeleFWIMData->lastPhyControl = pPeleRegs->phyControl;
- phyData = EndianSwap32Bit (pPeleFWIMData->lastPhyControl);
-
- // If it was register 0 that came in, do some more work:
-
- if (((phyData & kPelePhyControlRdAddr) >> kPelePhyControlRdAddrPhase) == 0)
- {
- phyData = (phyData & kPelePhyControlRdData) >> kPelePhyControlRdDataPhase;
- pPeleFWIMData->lastPhyReg0 = phyData;
-
- // If there was a bus reset, and we were cycle master, and we aren't any more,
- // we need to turn off the cycle master ASAP. For one thing, we probably will
- // not receive cycle start packets as long as kPeleControlCycleMaster is set.
- // There may be other reasons to do this too (hardware bugs).
-
- if ((phyData & kPelePhyR) == 0) // if not root
- {
- if (pPeleRegs->control & EndianSwapImm32Bit (kPeleControlCycleMaster))
- {
- // zzz
- // There are some possible race conditions here.
- // We could still be turning on cycle master due to a previous config.
- // One solution might be to (when we want to do that) cause a PHY read
- // that will bring us here, then turn it on here.
-
- // Disable cycle mastering.
- pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
- SynchronizeIO ();
- }
- }
- }
- }
- #endif
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMHandleMiscInterrupt
- //
- // This proc handles miscellaneous interrupts.
- // This is only called #ifdef PeleFireBug
- // zzz no mechanism to prevent race condition in reporting.
- //
-
- static void PeleFWIMHandleMiscInterrupt(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- OSStatus status = noErr;
-
- pPeleFWIMData->miscInterrupt = EndianSwap32Bit (
- pPeleFWIMData->pPeleRegisters->interruptEvents &
- pPeleFWIMData->pPeleRegisters->interruptMask);
-
- // Schedule deferred task.
- if ((pPeleFWIMData->miscInterrupt) && !(pPeleFWIMData->miscInterruptDTScheduled))
- {
- status = FWScheduleDeferredTask (pPeleFWIMData->miscInterruptDeferredTaskID, nil);
-
- if (status == noErr)
- pPeleFWIMData->miscInterruptDTScheduled = true;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMResetBus
- //
- // This routine initiates a bus reset.
- //
-
- static OSStatus PeleFWIMResetBus(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- UInt32 phyReg;
- OSStatus status = noErr;
-
- // Get our internal data.
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- #ifdef PeleFireBug
- sprintf (fireBug, "PeleFWIM: Bus reset from FSL");
- PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
- #endif
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Get base address of Pele registers.
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Issue the reset.
- phyReg = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyIBRAddress);
- phyReg |= kPelePhyIBR;
- PeleFWIMWritePhyRegister (pPeleRegs, kPelePhyIBRAddress, phyReg);
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMSetContenderBit
- //
- // This routine sets the contender bit in the self ID on the next bus reset.
- // zzz NYI - different boards do this in different ways
-
- static OSStatus PeleFWIMSetContenderBit(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Program the contender bit to be set on next reset.
- SynchronizeIO ();
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMClearContenderBit
- //
- // This routine clears the contender bit in the self ID on the next bus reset.
- // zzz see above
-
- static OSStatus PeleFWIMClearContenderBit(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Program the contender bit to be clear on next reset.
- SynchronizeIO ();
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMEnableCycleMaster
- //
- // This routine enables cycle mastering.
- // Unlike the disable routine below, which is somewhat redundant, this routine
- // is the only place we set cycle master. Setting cycle master is done only
- // after the IRM assigns a new cycle master, which is rare and isn't supposed
- // to be particularly fast. (ie, cycle loss is OK)
- //
- // zzz should there be a mechanism to report failure, such as FSL asked us to
- // become cyclemaster, but by the time we got here, we aren't root anymore?
- //
-
- static OSStatus PeleFWIMEnableCycleMaster(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Enable cycle mastering if we're root.
- // There is a race condition: We could lose root before we turn on the cycle
- // master, and then turn it on. In theory Pele won't send cycleStart if it is
- // not root, but it probably won't accept them if we leave the cycle master bit
- // turned on, so we'll still be messed up. So, after turning it on, make sure
- // we're still root, and if not, turn it back off. This is the only place it
- // can be turned on, so then we should be OK.
-
- if (pPeleFWIMData->root)
- {
- // For safety, triple-check that we're root:
- if ((((volatile UInt8) (pPeleFWIMData->lastPhyReg0)) & kPelePhyR) &&
- (pPeleRegs->nodeID & EndianSwapImm32Bit (kPeleNodeIDRoot)) &&
- (pPeleRegs->nodeID & EndianSwapImm32Bit (kPeleNodeIDValid)))
- {
- pPeleRegs->control |= EndianSwapImm32Bit (kPeleControlCycleMaster);
- SynchronizeIO ();
-
- // And now, if we lost root, we may have screwed up control.
- // This isn't perfect, but at least turn off the CYCMASTER
-
- if ((!(((volatile UInt8) (pPeleFWIMData->lastPhyReg0)) & kPelePhyR)) ||
- !(pPeleRegs->nodeID & EndianSwapImm32Bit (kPeleNodeIDRoot)) ||
- !(pPeleRegs->nodeID & EndianSwapImm32Bit (kPeleNodeIDValid)))
- {
- pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
- SynchronizeIO ();
- }
- }
- }
-
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDisableCycleMaster
- //
- // This routine disables cycle mastering.
- // Note, this is somewhat redundant, because we will have turned off cycle
- // mastering at primary interrupt level as soon as we lose root status. The
- // only case in which this function would really do anything is if FSL wanted
- // to stop being the cycle master even though we are the root node.
- //
-
- static OSStatus PeleFWIMDisableCycleMaster(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Disable cycle mastering.
- pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
- SynchronizeIO ();
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMSetRootHoldoffBit
- //
- // This routine sets the PHY root holdoff bit.
- //
-
- static OSStatus PeleFWIMSetRootHoldoffBit(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- UInt32 phyReg;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Set the root holdoff bit in the PHY.
- phyReg = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyRHBAddress);
- phyReg |= kPelePhyRHB;
- PeleFWIMWritePhyRegister (pPeleRegs, kPelePhyRHBAddress, phyReg);
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMClearRootHoldoffBit
- //
- // This routine clears the PHY root holdoff bit.
- //
-
- static OSStatus PeleFWIMClearRootHoldoffBit(
- FWIMCommandParamsPtr pFWIMCommandParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- UInt32 phyReg;
- OSStatus status = noErr;
-
- // Get our internal data and register base address.
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Clear the root holdoff bit in the PHY.
- phyReg = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyRHBAddress);
- phyReg &= ~kPelePhyRHB;
- PeleFWIMWritePhyRegister (pPeleRegs, kPelePhyRHBAddress, phyReg);
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMGetUniqueID
- //
- // This routine returns the local unique ID.
- //
-
- static OSStatus PeleFWIMGetUniqueID(
- FWIMGetUniqueIDParamsPtr pFWIMGetUniqueIDParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMGetUniqueIDParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- #if 0
- if (pPeleFWIMData->eepromValid)
- {
- pFWIMGetUniqueIDParams->uniqueID.hi = pPeleFWIMData->eepromInfo.busInfoBlock[2];
- pFWIMGetUniqueIDParams->uniqueID.lo = pPeleFWIMData->eepromInfo.busInfoBlock[3];
- }
- else
- #endif
- {
- //zzz Fake it
- pFWIMGetUniqueIDParams->uniqueID.hi = 'pele';
- pFWIMGetUniqueIDParams->uniqueID.lo = (UInt32) pPeleFWIMData;
- }
-
- // sprintf (debugStr, "PeleFWIMGetUniqueID : Node Vendor ID %06lx Chip ID %02lx%08lx",
- // (long) pFWIMGetUniqueIDParams->uniqueID.hi >> 8,
- // (long) pFWIMGetUniqueIDParams->uniqueID.hi & 0xff,
- // (long) pFWIMGetUniqueIDParams->uniqueID.lo);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMSendLinkOnPacket
- //
- // This proc sends the given link on packet.
- //
-
- static OSStatus PeleFWIMSendLinkOnPacket(
- FWIMSendPhyPacketParamsPtr pFWIMSendPhyPacketParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- UInt32 linkOnData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Check if generation is up to date.
- if ((!(pPeleFWIMData->generationValid)) ||
- (pFWIMSendPhyPacketParams->generation != pPeleFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
-
- // Set up link on data.
- if (status == noErr)
- {
- linkOnData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
- linkOnData &= ~kFWPhyPacketID;
- linkOnData |= kFWLinkOnPacketID << kFWPhyPacketIDPhase;
- }
-
- // Send packet.
- if (status == noErr)
- {
- PeleFWIMWriteAT (pPeleFWIMData, kFWSpeed100MBit, 3,
- 0x0E << kPelePacketTCodePhase,
- linkOnData, ~linkOnData, 0, 0, 0);
- }
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMSendPhyConfigurationPacket
- //
- // This proc sends the given Phy configuration packet.
- //
-
- static OSStatus PeleFWIMSendPhyConfigurationPacket(
- FWIMSendPhyPacketParamsPtr pFWIMSendPhyPacketParams,
- UInt32 *pCommandAcceptance)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- FWIMCommandParamsPtr pFWIMCommandParams;
- UInt32 configurationData;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Check if generation is up to date.
- if ((!(pPeleFWIMData->generationValid)) ||
- (pFWIMSendPhyPacketParams->generation != pPeleFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
-
- // Set up phy configuration data.
- if (status == noErr)
- {
- configurationData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
- configurationData &= ~kFWPhyPacketID;
- configurationData |= kFWConfigurationPacketID << kFWPhyPacketIDPhase;
- }
-
- // Send packet.
- if (status == noErr)
- {
- PeleFWIMWriteAT (pPeleFWIMData, kFWSpeed100MBit, 3,
- (0x0E << kPelePacketTCodePhase),
- configurationData, ~configurationData, 0, 0, 0);
- }
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMWritePhyRegister
- //
- // This proc writes data to the specified phy register.
- // There's really no way to confirm the write, so we return immediately.
- //
-
- static void PeleFWIMWritePhyRegister(
- PeleRegistersPtr pPeleRegs,
- UInt8 regAddress,
- UInt8 regData)
- {
- UInt32 phyChipAccess;
- AbsoluteTime absoluteDuration;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMWritePhyRegister");
-
- // Set up phyChipAccess to write phy.
- // Set the write bit, the register address, and data.
- phyChipAccess = kPelePhyControlWrReg;
- phyChipAccess |= (regAddress << kPelePhyControlWrAddrPhase);
- phyChipAccess |= (regData << kPelePhyControlWrDataPhase);
- pPeleRegs->phyControl = EndianSwap32Bit (phyChipAccess);
- SynchronizeIO ();
-
- // Give it a little time to finish before we try anything else.
- absoluteDuration = DurationToAbsolute (100 * durationMicrosecond);
- DelayForHardware (absoluteDuration);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMReadPhyRegister
- //
- // This proc reads data from the specified phy register.
- //
- // Execpt for initialization, this routine is called only from deferred tasks
- // and/or secondary interrupt level, so it should not re-enter. Rather than
- // polling the hardware, we'll wait for the interrupt when a phy register arrives.
- // lastPhyControl will be updated by an interrupt handler any time a PHY status
- // transfer sends back a PHY register value.
- //
- // If PELE_NO_PHY_REG_RCVD is defined, we have to poll the PHY control instead.
-
- static UInt8 PeleFWIMReadPhyRegister(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleRegistersPtr pPeleRegs,
- UInt8 regAddress)
- {
- UInt32 phyChipAccess, phyChipAccessRead;
- UInt8 returnedAddress, regData;
- UInt32 patience = 100, done = 0;
- AbsoluteTime absoluteDuration;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMReadPhyRegister");
-
- // Set up phyChipAccessRead to read phy.
- phyChipAccessRead = kPelePhyControlRdReg;
- phyChipAccessRead |= (regAddress << kPelePhyControlWrAddrPhase);
-
- while (!done)
- {
- // Clear the return area and then request a PHY register read.
- // In normal operation, we should get an answer back in less than a millisecond.
-
- (volatile UInt32) (pPeleFWIMData->lastPhyControl) = 0xFFFFFFFF;
- SynchronizeIO ();
- pPeleRegs->phyControl = EndianSwap32Bit (phyChipAccessRead);
- SynchronizeIO ();
-
- // This will make the Mac sluggish if there is a storm of resets.
- absoluteDuration = DurationToAbsolute (durationMillisecond);
- DelayForHardware (absoluteDuration);
-
- #ifdef PELE_NO_PHY_REG_RCVD
- phyChipAccess = pPeleRegs->phyControl;
-
- // If rdDone isn't set after a millisecond, it probably never will be.
- // This will cause us to try again.
-
- if (!(phyChipAccess & EndianSwapImm32Bit (kPelePhyControlRdDone)))
- phyChipAccess = 0xFFFFFFFF;
- #else
- phyChipAccess = (volatile UInt32) pPeleFWIMData->lastPhyControl;
- #endif
-
- if (phyChipAccess == 0xFFFFFFFF)
- {
- // No response
- sprintf (debugStr, "PeleFWIMReadPhyRegister, no response from PHY [%08lx]",
- (long) EndianSwap32Bit (pPeleRegs->phyControl));
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- else
- {
- phyChipAccess = EndianSwap32Bit (phyChipAccess);
- returnedAddress = (phyChipAccess & kPelePhyControlRdAddr) >> kPelePhyControlRdAddrPhase;
-
- if (returnedAddress == regAddress)
- {
- // Got the register we wanted
- regData = (phyChipAccess & kPelePhyControlRdData) >> kPelePhyControlRdDataPhase;
- done = 1;
- }
- }
-
- if ((!done) && !(patience--))
- {
- done = 1;
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMReadPhyRegister, PHY seems to be jammed");
- // set FWIM global failure indication
- }
- }
-
- return regData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddAsynchRxDMA
- //
- // This proc adds a descriptor to the active asynch receive DMA list.
- //
-
- static void PeleFWIMAddAsynchRxDMA(
- PeleAsynchRxDMADataPtr pPeleAsynchRxDMAData)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleAsynchRxDMADataPtr pPrevPeleAsynchRxDMAData,
- pOverflowPeleAsynchRxDMAData;
- PeleDMAPtr pDMA,
- pPrevDMA,
- pOverflowDMA;
-
- // Get PCL data and Pele FWIM data for PCL to add.
- pDMA = pPeleAsynchRxDMAData->pDMA;
- pPeleFWIMData = pPeleAsynchRxDMAData->pPeleFWIMData;
-
- // Get data for overflow handling.
- pOverflowPeleAsynchRxDMAData = pPeleFWIMData->asynchRxOverflowDMASegment;
- pOverflowDMA = pOverflowPeleAsynchRxDMAData->pDMA;
-
- // Link new descriptor to overflow handler and invalidate status.
- pDMA->cmdDep = EndianSwap32Bit ((UInt32) pOverflowPeleAsynchRxDMAData->pDMAPhysical);
- pDMA->result = EndianSwapImm32Bit (0);
- pPeleAsynchRxDMAData->pNextRxDMAData = nil;
-
- // Get last asynch receive PCL.
- pPrevPeleAsynchRxDMAData = pPeleFWIMData->pLastAsynchRxDMAData;
-
- // Link new PCL to last one.
- if ((pPrevPeleAsynchRxDMAData != nil) && (pPeleFWIMData->pNextAsynchRxDMAData != nil))
- {
- pPrevDMA = pPrevPeleAsynchRxDMAData->pDMA;
- pPrevDMA->cmdDep = EndianSwap32Bit ((UInt32) pPeleAsynchRxDMAData->pDMAPhysical);
- pPrevPeleAsynchRxDMAData->pNextRxDMAData = pPeleAsynchRxDMAData;
- }
- else
- {
- pPeleFWIMData->pNextAsynchRxDMAData = pPeleAsynchRxDMAData;
- }
-
- // Check for overflow.
- if (pPeleFWIMData->asynchRxOverflowFlag)
- {
- // Restart asynch receive PCL program at new PCL if it's still unused.
- if (pDMA->result == EndianSwapImm32Bit (0))
- PeleFWIMStartAsynchRxDMAProgram (pPeleFWIMData, pPeleAsynchRxDMAData);
- }
-
- // New PCL is now last.
- pPeleFWIMData->pLastAsynchRxDMAData = pPeleAsynchRxDMAData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMCreateAsynchRxDMAProgram
- //
- // This proc creates the asynch receive DMA program.
- //
-
- static void PeleFWIMCreateAsynchRxDMAProgram(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- PeleFWIMDataPtr pPhysPeleFWIMData;
- PeleAsynchRxDMADataPtr pPeleAsynchRxDMAData;
- PeleDMAPtr pDMA;
- UInt32 dmaNum,
- packetNum;
-
- // Get physical pointer to FWIM data.
- pPhysPeleFWIMData = pPeleFWIMData->fwimDataPhys;
-
- // Create overflow segment.
- PeleFWIMCreateAsynchRxOverflowDMASegment (pPeleFWIMData);
-
- // Create packet descriptors.
- for (dmaNum = kAsynchRxFirstPacketDMA, packetNum = 0;
- dmaNum <= kAsynchRxLastPacketDMA;
- dmaNum++, packetNum++)
- {
- // Get pointer to descriptor.
- pDMA = &(pPeleFWIMData->asynchDMA[dmaNum]);
-
- // Add DMA data record.
- pPeleAsynchRxDMAData = &(pPeleFWIMData->asynchRxDMADataList[dmaNum]);
- //pPeleAsynchRxDMAData->pNextPCLData will be filled in by AddAsynchRxDMA
- pPeleAsynchRxDMAData->pPeleFWIMData = pPeleFWIMData;
- pPeleAsynchRxDMAData->pDMA = pDMA;
- pPeleAsynchRxDMAData->pDMAPhysical =
- pPeleFWIMData->asynchDMAPhys + (dmaNum * sizeof (PeleDMA));
- pPeleAsynchRxDMAData->packetBuffer = pPeleFWIMData->asynchBuf[packetNum];
- //pPeleAsynchRxDMAData->fwimProcessAsynchParams will be filled in when a packet arrives
-
- // Initialize DBDMA descriptor.
- pDMA->operation =
- EndianSwapImm32Bit (kPeleINPUT_LAST | // Entire packet in one buffer
- kPeleKEY_STREAM0 | // Only STREAM implemented
- kPeleIntAlways | // Interrupt when done
- kPeleBranchAlways | // Branch to next descriptor
- kPeleWaitNever | // No wait
- kAsyncRxPacketBufferSize); // reqCount
- pDMA->address = EndianSwap32Bit ((UInt32) pPeleFWIMData->asynchBufPhys[packetNum]);
- pDMA->cmdDep = EndianSwapImm32Bit (0); // branch address - will be filled in later.
- pDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- // Add descriptor to program.
- PeleFWIMAddAsynchRxDMA (pPeleAsynchRxDMAData);
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMCreateAsynchRxOverflowDMASegment
- //
- // This proc creates the asynch receive overflow DMA segment.
- //zzz what should happen if we get to end of list?
- //
-
- static void PeleFWIMCreateAsynchRxOverflowDMASegment(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- PeleFWIMDataPtr pPhysPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- PeleAsynchRxDMADataPtr pPeleAsynchRxDMAData;
- PeleDMAPtr pDMA;
-
- // This DBDMA goes at the end of the asynch receive program. If we run out
- // of asynch receive descriptors, we want to do a controlled shutdown so that we
- // send the right ack code on any future packets (ack_busyX). So this program
- // sets some bits that causes ack_busyX for all packets. That way, packets don't
- // pile up in the receive FIFO.
-
- // At present, some packets could be in the FIFO by the time we set the busyX
- // bits. Those packets will linger there until we recover, and they will
- // block any incoming isoch packets. That's not good. We should add more PCLs
- // after this one that will drain the FIFO (but not bitbucket the packets).
-
- // Get pointer to link registers and physical pointer to FWIM data.
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
- pPhysPeleFWIMData = pPeleFWIMData->fwimDataPhys;
-
- // Set up program to busy incoming packets.
- // First STORE_QUAD into the packetControl register to select busyX,
- // then STORE_QUAD into pPeleFWIMData so software knows we did this,
- // then STOP.
- // Note, if we ever manipulated the packetControl register, we'd have to update
- // this program. But at present, this is the only way we touch packetControl
- // after initialization.
-
- // This assumes that for Pele register addresses, virtual == physical.
- // For the FWIM data though, we must convert:
-
- pPhysPeleFWIMData = pPeleFWIMData->fwimDataPhys;
-
- pDMA = &(pPeleFWIMData->asynchDMA[kAsynchRxOverrunDMA]);
- pPeleAsynchRxDMAData = &(pPeleFWIMData->asynchRxDMADataList[kAsynchRxOverrunDMA]);
- pPeleAsynchRxDMAData->pPeleFWIMData = pPeleFWIMData;
- pPeleAsynchRxDMAData->pDMA = pDMA;
- pPeleAsynchRxDMAData->pDMAPhysical =
- pPeleFWIMData->asynchDMAPhys + (kAsynchRxOverrunDMA * sizeof (PeleDMA));
-
- pDMA->operation = EndianSwapImm32Bit (kPeleSTORE_QUAD |
- kPeleKEY_SYSTEM | // works on registers too
- 4); // reqCount
- pDMA->address = EndianSwap32Bit ((UInt32) &(pPeleRegs->packetControl));
- pDMA->cmdDep = EndianSwapImm32Bit (kPeleBsyCtrlAlwaysSendBusyX |
- kPelePacketControlRcvSelfID );
-
- pDMA++;
- pDMA->operation = EndianSwapImm32Bit (kPeleSTORE_QUAD |
- kPeleKEY_SYSTEM |
- 4);
- pDMA->address = EndianSwap32Bit ((UInt32) &(pPhysPeleFWIMData->asynchRxOverflowFlag));
- pDMA->cmdDep = EndianSwapImm32Bit (0xFFFFFFFF);
-
- pDMA++;
- pDMA->operation = EndianSwapImm32Bit (kPeleSTOP_CMD);
-
- // Set PCL segment in FWIM data.
- pPeleFWIMData->asynchRxOverflowDMASegment = pPeleAsynchRxDMAData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMStartAsynchRxDMAProgram
- //
- // This proc starts the asynch receive DMA program.
- //
-
- static void PeleFWIMStartAsynchRxDMAProgram(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pPeleAsynchRxDMAData)
- {
- PeleRegistersPtr pPeleRegs;
- PeleAsynchRxDMADataPtr pStartPeleAsynchRxDMAData;
- Boolean asynchRxReady = false;
-
- // Get pointer to link registers and start PCL's data.
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Check for overflow.
- if (pPeleFWIMData->asynchRxOverflowFlag)
- {
- // Check if we've started priming.
- if (pPeleFWIMData->numAsynchRxDMAsPrimed == 0)
- {
- pPeleFWIMData->pStartAsynchRxDMAData = pPeleAsynchRxDMAData;
- pPeleFWIMData->numAsynchRxDMAsPrimed = 1;
- }
- else
- {
- pPeleFWIMData->numAsynchRxDMAsPrimed++;
- }
-
- // Check if we've primed enough receive PCLs.
- if (pPeleFWIMData->numAsynchRxDMAsPrimed >= kPeleNumAsynchRxDMAsToPrime)
- {
- pPeleFWIMData->asynchRxOverflowFlag = 0;
- pPeleFWIMData->numAsynchRxDMAsPrimed = 0;
- asynchRxReady = true;
- }
- }
- else
- {
- // We're ready to receive.
- pPeleFWIMData->pStartAsynchRxDMAData = pPeleAsynchRxDMAData;
- asynchRxReady = true;
- }
-
- if (asynchRxReady)
- {
- // Quiet the DMA channel.
- pPeleRegs->asynchReceive.channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO();
-
- // Start the program at the given descriptor.
- pStartPeleAsynchRxDMAData = pPeleFWIMData->pStartAsynchRxDMAData;
-
- // Set DMA command pointer
- pPeleRegs->asynchReceive.commandPtr =
- EndianSwap32Bit ((UInt32) pStartPeleAsynchRxDMAData->pDMAPhysical);
- SynchronizeIO();
-
- // Enable the DMA.
- pPeleRegs->asynchReceive.channelControl = EndianSwapImm32Bit (kPeleSetRun);
- SynchronizeIO();
-
- // Clear busy flag in packetControl register.
- // Only we clear this, only the DMA sets this.
- // Until we clear this, nothing will arrive in the DMA, so there's no race.
- pPeleRegs->packetControl = EndianSwapImm32Bit (kPelePacketControlRcvSelfID);
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddAsynchTxDMA
- //
- // This proc adds a DMA to the active asynch transmit DMA list.
- //
-
- static void PeleFWIMAddAsynchTxDMA(
- PeleAsynchTxDMADataPtr pTxDMAData)
- {
- PeleFWIMDataPtr pPeleFWIMData;
- PeleAsynchTxDMADataPtr pPrevTxDMAData,
- pDoneTxDMAData;
- PeleDMAPtr pDMA,
- pPrevDMA,
- pDoneDMA;
-
- // Get PCL data and Pele FWIM data for PCL to add.
- pDMA = pTxDMAData->pDMA;
- pPeleFWIMData = pTxDMAData->pPeleFWIMData;
-
- // Get PCL and PCL data for done handling.
- pDoneTxDMAData = pPeleFWIMData->asynchTxDoneDMASegment;
- pDoneDMA = pDoneTxDMAData->pDMA;
-
- // Link new PCL to done handler and invalidate new PCL's status.
- //zzz this is done by BuildAsyncTxDMA, because the final point can vary.
- // pDMA->cmdDep = EndianSwap32Bit ((UInt32) pDoneTxDMAData->pDMAPhysical);
- // pDMA->operation |= EndianSwapImm32Bit (kPeleBranchAlways);
- pTxDMAData->pNextTxDMAData = nil;
- // duplicate? zzz
- pDMA->result = EndianSwapImm32Bit (0);
-
- // Get last asynch transmit PCL.
- pPrevTxDMAData = pPeleFWIMData->pLastAsynchTxDMAData;
-
- // Link new PCL to last one.
- if ((pPrevTxDMAData != nil) && (pPeleFWIMData->pNextAsynchTxDMAData != nil))
- {
- pPrevDMA = pPrevTxDMAData->pDMA;
- pPrevDMA->cmdDep = EndianSwap32Bit ((UInt32) pTxDMAData->pDMAPhysical);
- pPrevTxDMAData->pNextTxDMAData = pTxDMAData;
- }
- else
- {
- pPeleFWIMData->pNextAsynchTxDMAData = pTxDMAData;
- }
-
- // Check for asynchronous transmit done.
- if (pPeleFWIMData->asynchTxDoneFlag)
- {
- // Restart asynch transmit PCL program at new PCL if it's still unused.
- if (pDMA->result == EndianSwapImm32Bit (0))
- PeleFWIMStartAsynchTxDMAProgram (pPeleFWIMData, pTxDMAData);
- }
-
- // New PCL is now last.
- pPeleFWIMData->pLastAsynchTxDMAData = pTxDMAData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMCreateAsynchTxDoneDMASegment
- //
- // This proc creates the asynch transmit done DMA segment.
- //
-
- static void PeleFWIMCreateAsynchTxDoneDMASegment(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- PeleFWIMDataPtr pPhysPeleFWIMData;
- PeleAsynchTxDMADataPtr pTxDMAData;
- PeleDMAPtr pDMA;
-
- // Get physical pointer to FWIM data.
- pPhysPeleFWIMData = pPeleFWIMData->fwimDataPhys;
-
- // need two descriptors - store quad and STOP.
-
- // Set up descriptors to set done flag.
- pDMA = &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDoneDMA]);
- pDMA->operation = EndianSwapImm32Bit (kPeleSTORE_QUAD |
- kPeleKEY_SYSTEM |
- kPeleIntNever |
- kPeleBranchNever |
- kPeleWaitNever |
- 4); // reqCount
- pDMA->address = EndianSwap32Bit ((UInt32) &(pPhysPeleFWIMData->asynchTxDoneFlag));
- pDMA->cmdDep = EndianSwapImm32Bit (0xFFFFFFFF);
- pDMA->result = EndianSwapImm32Bit (0);
-
- pDMA = &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDoneDMA + 1]);
- pDMA->operation = EndianSwapImm32Bit (kPeleSTOP_CMD |
- kPeleIntNever |
- kPeleBranchNever |
- kPeleWaitNever);
- pDMA->address = EndianSwapImm32Bit (0);
- pDMA->cmdDep = EndianSwapImm32Bit (0);
- pDMA->result = EndianSwapImm32Bit (0);
-
- pTxDMAData = &(pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDoneDMA]);
- pTxDMAData->pPeleFWIMData = pPeleFWIMData;
- pTxDMAData->pDMA = &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDoneDMA]);
- pTxDMAData->pDMAPhysical =
- pPeleFWIMData->asynchXmitDMAPhys + (kAsynchTxDoneDMA * sizeof (PeleDMA));
-
- // Set done flag.
- pPeleFWIMData->asynchTxDoneFlag = 0xFFFFFFFF;
- pPeleFWIMData->pLastAsynchTxDMAData = nil;
-
- // Note in FWIM data.
- pPeleFWIMData->asynchTxDoneDMASegment = pTxDMAData;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMCreateAsynchTxDataDMA
- //
- // This proc creates a data DMA for the asynch transmit DMA program.
- //
-
- static void PeleFWIMCreateAsynchTxDataDMA(
- PeleFWIMDataPtr pPeleFWIMData)
- {
- PeleAsynchTxDMADataPtr pTxDMAData;
-
- // Just fill in the basics.
- // This single data pointer points to a block of consecutive descriptors.
-
- pTxDMAData = &(pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDataDMA]);
- pTxDMAData->pPeleFWIMData = pPeleFWIMData;
- pTxDMAData->pDMA = &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDataDMA]);
- pTxDMAData->pDMAPhysical =
- pPeleFWIMData->asynchXmitDMAPhys + (kAsynchTxDataDMA * sizeof (PeleDMA));
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMStartAsynchTxDMAProgram
- //
- // This proc starts the asynch transmit DMA program.
- //
-
- static void PeleFWIMStartAsynchTxDMAProgram(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchTxDMADataPtr pStartTxDMAData)
- {
- PeleRegistersPtr pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Clear done flag.
- pPeleFWIMData->asynchTxDoneFlag = 0;
-
- // Clear ack status in end segment.
- pPeleFWIMData->asynchTxDoneDMASegment->pDMA->result = EndianSwapImm32Bit (0);
-
- // Quiet the DMA channel.
- pPeleRegs->asynchTransmit.channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO();
-
- // Start the program at the given descriptor.
- pPeleRegs->asynchTransmit.commandPtr =
- EndianSwap32Bit ((UInt32) pStartTxDMAData->pDMAPhysical);
- SynchronizeIO();
-
- // Enable the DMA.
- pPeleRegs->asynchTransmit.channelControl = EndianSwapImm32Bit (kPeleSetRun);
- SynchronizeIO();
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMWriteAT
- //
- // Common code for writing an ATF packet
- //
-
- static OSStatus PeleFWIMWriteAT(
- PeleFWIMDataPtr pPeleFWIMData,
- UInt32 speed,
- UInt32 baseCount, // count [1-4] of quads below:
- UInt32 data1,
- UInt32 data2,
- UInt32 data3,
- UInt32 data4,
- UInt32 extCount, // count in BYTES of data below:
- UInt32 *extData)
- {
- PeleRegistersPtr pPeleRegs;
- IOPreparationID ioPreparationID;
- UInt32 dataBuffer[4];
- AbsoluteTime timeoutAbsolute, timeLeft;
- UInt32 patience;
- OSStatus status = noErr;
-
- // Get pointer to link registers.
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Set up descriptor.
- dataBuffer[0] = data1;
- dataBuffer[1] = data2;
- dataBuffer[2] = data3;
- dataBuffer[3] = data4;
-
- // If we queued multiple transmits, this would matter. But we only send one
- // packet at a time. We could get a bus reset just before we activate the
- // transmitter, but there's nothing we can do in software to avoid that.
-
- // Note, some older Pele designs don't use the EnableAT bit in the ATDMA.
- // Setting it should be harmless (and useless) on such parts.
-
- dataBuffer[0] |= kPelePacketEnableAT;
-
- // This assumes that baseCount is at least 1. All async DMA puts the speed here:
-
- if (speed == kFWSpeed200MBit)
- dataBuffer[0] |= (kPeleDMA200mbps << kPelePacketSpdPhase);
-
- if (speed == kFWSpeed400MBit)
- dataBuffer[0] |= (kPeleDMA400mbps << kPelePacketSpdPhase);
-
- dataBuffer[0] |= kPelePacketEnableAT; //zzz Not sure there's any better way
-
- PeleFWIMBuildAsynchTxDMA (pPeleFWIMData,
- &(pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDataDMA]),
- &ioPreparationID,
- (Ptr) &dataBuffer[0],
- baseCount * sizeof (UInt32),
- (Ptr) extData,
- extCount);
-
- // Add data PCL to asynch transmit program and start.
- PeleFWIMAddAsynchTxDMA (&(pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDataDMA]));
-
- // This still isn't great. We should just return, and then handle completion or
- // failure later, when an interrupt or timer goes off.
-
- // Wait for asynch transmit program to end, or TX to be disabled (due to bus reset).
- // Check TX disable only once per millisecond. Try this for at most 50 milliseconds.
-
- timeoutAbsolute =
- AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationMillisecond));
- patience = 50;
-
- while (!(pPeleFWIMData->asynchTxDoneFlag))
- {
- // It's probably not necessary to do this any more. The reset primary handler
- // Will stop the DMA and mark it as done if there is a bus reset while we try
- // to transmit.
- // Check only rarely for bus reset
- timeLeft = SubAbsoluteFromAbsolute (UpTime (), timeoutAbsolute); // returns 0 if negative
- if (AbsoluteToDuration (timeLeft) == 0)
- {
- if ((!patience) || !(EndianSwap32Bit(pPeleRegs->control) & kPeleControlTransmitEnable))
- {
- pPeleRegs->asynchTransmit.channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO ();
- pPeleFWIMData->asynchTxDoneFlag = 0xFFFFFFFF;
- }
- else
- {
- timeoutAbsolute =
- AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationMillisecond));
- patience--;
- }
- }
- }
-
- // Clean up transmission.
- CheckpointIO (ioPreparationID, kNilOptions);
-
- // Streaming is NYI, so this is always nil.
- pPeleFWIMData->pNextAsynchTxDMAData =
- pPeleFWIMData->AsynchTxDMADataList[kAsynchTxDataDMA].pNextTxDMAData;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMBuildAsynchTxDMA
- //
- // This proc builds an asynchronous transmit PCL from the given parameters.
- // buffer1 is assumed to be small. It is usually a packet header. buffer2 is
- // assumed to be larger and typically is a packet payload.
- //
-
- static OSStatus PeleFWIMBuildAsynchTxDMA(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchTxDMADataPtr pTxDMAData,
- IOPreparationID *pIOPreparationID,
- Ptr buffer1,
- UInt32 size1,
- Ptr buffer2,
- UInt32 size2)
- {
- IOPreparationTable ioPreparationTable;
- PeleDMAPtr pDMA;
- PhysicalAddress physicalMapping[kMaxBufPage];
- UInt32 pageSize,
- pageShift;
- UInt32 numPages;
- Ptr preparedBuffer;
- UInt32 seg1Size,
- seg2Size;
- UInt32 seg2AlignSize;
- UInt32 transferSize;
- UInt32 dmaBufferNum;
- UInt32 pageNum;
- OSStatus status = noErr;
-
- // Get some FWIM parameters.
- pageSize = pPeleFWIMData->pageSize;
- pageShift = pPeleFWIMData->pageShift;
- preparedBuffer = pPeleFWIMData->asynchXmitBuf;
-
- // Do initial DMA set up.
- pDMA = pTxDMAData->pDMA;
- pDMA->result = EndianSwapImm32Bit (0);
-
- // Set up initial segment sizes, PCL buffer number, and ioPreparationTable.
- seg1Size = size1;
- seg2Size = size2;
- dmaBufferNum = 0;
- ioPreparationTable.preparationID = kInvalidID;
-
- // Add buffer1 to our prepared buffer.
- if (size1 > 0)
- {
- BlockCopy (buffer1, preparedBuffer, size1);
- preparedBuffer += size1;
- }
-
- // Add data from buffer2 to our prepared buffer to 32 byte align second segment.
- if ((((UInt32) buffer2) & 31) > 0)
- seg2AlignSize = 32 - (((UInt32) buffer2) & 31);
- else
- seg2AlignSize = 0;
- if (seg2AlignSize > size2)
- seg2AlignSize = size2;
- if (seg2AlignSize > 0)
- {
- BlockCopy (buffer2, preparedBuffer, seg2AlignSize);
- preparedBuffer += seg2AlignSize;
- seg1Size += seg2AlignSize;
- buffer2 += seg2AlignSize;
- seg2Size -= seg2AlignSize;
- }
-
- // Add prepared buffer to PCL.
- pDMA->operation = EndianSwap32Bit ((seg2Size ? kPeleOUTPUT_MORE : kPeleOUTPUT_LAST) |
- kPeleKEY_STREAM0 |
- kPeleIntNever |
- kPeleBranchNever |
- kPeleWaitNever |
- seg1Size);
- pDMA->address = EndianSwap32Bit ((UInt32) pPeleFWIMData->asynchXmitBufPhys);
- pDMA->cmdDep = EndianSwapImm32Bit (0);
- pDMA->result = EndianSwapImm32Bit (0);
-
- pDMA++;
- dmaBufferNum++;
-
- // Add rest of buffer2 to PCL.
- if (seg2Size > 0)
- {
- // Set up IO preparation table.
- numPages = ((((UInt32) buffer2) + seg2Size - 1) >> pageShift) -
- (((UInt32) buffer2) >> pageShift) + 1;
- ioPreparationTable.options = kIOLogicalRanges | kIOIsOutput;
- ioPreparationTable.addressSpace = kCurrentAddressSpaceID;
- ioPreparationTable.granularity = 0;
- ioPreparationTable.firstPrepared = 0;
- ioPreparationTable.mappingEntryCount = numPages;
- ioPreparationTable.logicalMapping = 0;
- ioPreparationTable.physicalMapping = physicalMapping;
- ioPreparationTable.rangeInfo.range.base = buffer2;
- ioPreparationTable.rangeInfo.range.length = seg2Size;
-
- // Prepare.
- status = PrepareMemoryForIO (&ioPreparationTable);
- /*zzz*/
- if (status != noErr)
- {
- sprintf (debugStr, "PrepareMemoryForIO error %ld", status);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- /*zzz*/
-
- // Add pages to PCL.
- if (status == noErr)
- {
- // Compute first page transfer size.
- if (numPages > 1)
- transferSize = pageSize - (((UInt32) buffer2) & (pageSize - 1));
- else
- transferSize = seg2Size;
-
- // Add first page to PCL.
- pDMA->operation = EndianSwap32Bit ((numPages > 1 ?
- kPeleOUTPUT_MORE : kPeleOUTPUT_LAST) |
- kPeleKEY_STREAM0 |
- kPeleIntNever |
- kPeleBranchNever |
- kPeleWaitNever |
- transferSize);
- pDMA->address = EndianSwap32Bit ((UInt32) physicalMapping[0]);
- pDMA->cmdDep = EndianSwapImm32Bit (0);
- pDMA->result = EndianSwapImm32Bit (0);
-
- pDMA++;
- dmaBufferNum++;
-
- // Add rest of pages except last one to PCL.
- for (pageNum = 1; pageNum < (numPages - 1); pageNum++)
- {
- // Add page to PCL.
- pDMA->operation = EndianSwap32Bit (kPeleOUTPUT_MORE |
- kPeleKEY_STREAM0 |
- kPeleIntNever |
- kPeleBranchNever |
- kPeleWaitNever |
- pageSize);
- pDMA->address = EndianSwap32Bit ((UInt32) physicalMapping[pageNum]);
- pDMA->cmdDep = EndianSwapImm32Bit (0);
- pDMA->result = EndianSwapImm32Bit (0);
-
- pDMA++;
- dmaBufferNum++;
- }
-
- // Add last page to PCL.
- if (numPages > 1)
- {
- transferSize = (((UInt32) buffer2) + seg2Size) & (pageSize - 1);
- pDMA->operation = EndianSwap32Bit (kPeleOUTPUT_LAST |
- kPeleKEY_STREAM0 |
- kPeleIntNever |
- kPeleBranchNever |
- kPeleWaitNever |
- transferSize);
- pDMA->address = EndianSwap32Bit ((UInt32) physicalMapping[numPages - 1]);
- pDMA->cmdDep = EndianSwapImm32Bit (0);
- pDMA->result = EndianSwapImm32Bit (0);
-
- pDMA++;
- dmaBufferNum++;
- }
- }
- }
-
- // Mark final descriptor to branch to done segment
- pDMA--;
- pDMA->operation |= EndianSwapImm32Bit (kPeleBranchAlways);
- pDMA->cmdDep = EndianSwap32Bit ((UInt32) pPeleFWIMData->asynchTxDoneDMASegment->pDMAPhysical);
-
- // Return ioPreparationID.
- if (status == noErr)
- *pIOPreparationID = ioPreparationTable.preparationID;
- else
- *pIOPreparationID = kInvalidID;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMRead
- //
- // This proc performs a read transaction on the FireWire bus.
- // We write the read command, the completion is handled elsewhere
- // when we get an interrupt for the receipt of the response.
- //zzz what if timer goes off before request goes out???
- //zzz check length against maximum packet size
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus PeleFWIMRead(
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- UInt32 data1, data2, data3, data4;
- AbsoluteTime timeoutAbsolute;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\p(Pele) PeleFWIMRead");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Check if generation is up to date.
- if ((!(pPeleFWIMData->generationValid)) ||
- (pFWIMAsynchCommandParams->generation != pPeleFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
-
- // Warning - it is ESSENTIAL that reads which fail trigger the timeout handler.
- // FSL can't handle reads that just "vanish". But, rather than go thru the handler,
- // maybe we can return a failure below.
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMRead - setting timer for failure");
- // Set a timeout timer.
- if (status == noErr)
- {
- timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- PeleFWIMReadRequestTimeoutHandler,
- pFWIMAsynchCommandParams,
- &(pPeleFWIMData->requestTimeoutTimerID));
- if (status == noErr)
- pPeleFWIMData->requestTimeoutTimerSet = true;
- }
-
- // sometimes FSL tries to read from the local node, which won't work.
- // rather than bothering the DMA engine, just let the timeout timer
- // return the error. (return now - NYI)
-
- // Write read request to ATF.
- if (status == noErr)
- {
- // Need to send at correct speed (WriteAFT always sends at 100)
- pPeleFWIMData->transactionLabel =
- (pPeleFWIMData->transactionLabel + 1) & 0x3F;
-
- // Header quad common to quadlet and block:
- data1 = pPeleFWIMData->transactionLabel << kPeleAsynchTLabelPhase;
- data1 |= (kPeleAsynchNew << kPeleAsynchRtPhase);
-
- // Packet address same for both:
- data2 = pFWIMAsynchCommandParams->addressHi;
- data3 = pFWIMAsynchCommandParams->addressLo;
-
- if (pFWIMAsynchCommandParams->length == 4)
- { // Quadlet request.
-
- pPeleFWIMData->tCode = kFWTCodeReadQuadlet;
- data1 |= (kFWTCodeReadQuadlet << kPelePacketTCodePhase);
-
- PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchCommandParams->speed, 3, data1, data2, data3, 0, 0, 0);
- }
- else
- { // Block request.
-
- pPeleFWIMData->tCode = kFWTCodeReadBlock;
- data1 |= (kFWTCodeReadBlock << kPelePacketTCodePhase);
-
- data4 = pFWIMAsynchCommandParams->length << kPeleAsynchDataLengthPhase;
-
- PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
- }
- }
-
- // Complete command on error.
- if (status != noErr)
- {
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
- status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMReadResponse
- //
- // This proc sends a read response packet.
- //zzz check length against maximum packet size
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus PeleFWIMReadResponse(
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- UInt32 data1, data2, data4;
- UInt32 transactionLabel;
- UInt32 responseCode;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMResponseCommand =
- (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
-
- // Check if generation is up to date.
- if ((!(pPeleFWIMData->generationValid)) ||
- (pFWIMAsynchResponseCommandParams->generation != pPeleFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
-
- // Write read response to ATF.
- if (status == noErr)
- {
- // Compute transaction label and response code.
- transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
- kFWTransactionDescriptorTLabel) >>
- kFWTransactionDescriptorTLabelPhase;
- responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
- kFWResponseDataRCode) >>
- kFWResponseDataRCodePhase;
-
- // packet control header goes in quad 1
- data1 = transactionLabel << kPeleAsynchTLabelPhase;
- data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
-
- // packet destination node ID and response code go in quad 2
- data2 = pFWIMAsynchResponseCommandParams->destinationID << kPeleAsynchSourceIDPhase;
- data2 |= responseCode << kPeleAsynchRCodePhase;
-
- // packet payload goes in quad 4
- data4 = (*((UInt32 *) pFWIMAsynchResponseCommandParams->buffer));
-
- if (pFWIMAsynchResponseCommandParams->length == 4)
- { // Quadlet request.
-
- data1 |= kFWTCodeReadQuadletResponse << kPelePacketTCodePhase;
-
- PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, 0, 0);
- }
- else
- { // Block request.
-
- data1 |= kFWTCodeReadBlockResponse << kPelePacketTCodePhase;
-
- data4 = pFWIMAsynchResponseCommandParams->length << kPeleAsynchDataLengthPhase;
-
- PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
- }
- }
-
- // Complete command on error.
- //zzz assume success for now. should check ack code for success.
- //zzz if (status != noErr)
- {
- pPeleFWIMData->pPendingFWIMResponseCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
- status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMWrite
- //
- // This proc performs a write transaction on the FireWire bus.
- //zzz what if timer goes off before request goes out??? A: Execute this proc
- //zzz at secondary interrupt level
- //zzz check length against maximum packet size
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus PeleFWIMWriteTimer(
- void *p1,
- void *p2)
- {
- UInt32 commandAcceptance;
- OSStatus status = noErr;
-
- status = PeleFWIMWrite ((FWIMAsynchCommandParamsPtr) p1, &commandAcceptance);
- return (status);
- }
-
- static OSStatus PeleFWIMWrite(
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- OSStatus status = noErr;
- UInt32 data1, data2, data3, data4;
-
- static UInt32 debug = 0;
-
- // sprintf (debugStr, "FWIM Write %ld bytes", (long) pFWIMAsynchCommandParams->length);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Timer is off.
- pPeleFWIMData->requestTimeoutTimerSet = false;
-
- // Check if generation is up to date.
- if ((!(pPeleFWIMData->generationValid)) ||
- (pFWIMAsynchCommandParams->generation != pPeleFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
-
- //zzz need to set a timeout timer in case we get a ack_pending
-
- // Write write request to ATF.
- if (status == noErr)
- {
- if (pFWIMAsynchCommandParams->length == 4)
- { // Quadlet request.
- // Write packet control header.
-
- pPeleFWIMData->transactionLabel = (pPeleFWIMData->transactionLabel + 1) & 0x3F;
- pPeleFWIMData->tCode = kFWTCodeWriteQuadlet;
- data1 = pPeleFWIMData->transactionLabel << kPeleAsynchTLabelPhase;
- data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
- data1 |= kFWTCodeWriteQuadlet << kPelePacketTCodePhase;
-
- // Write packet address.
- data2 = pFWIMAsynchCommandParams->addressHi;
- data3 = pFWIMAsynchCommandParams->addressLo;
-
- // Write packet payload.
- data4 = (*((UInt32 *) pFWIMAsynchCommandParams->buffer));
-
- PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
- }
- else
- { // Block request.
- // Write packet control header.
-
- pPeleFWIMData->transactionLabel = (pPeleFWIMData->transactionLabel + 1) & 0x3F;
- pPeleFWIMData->tCode = kFWTCodeWriteBlock;
- data1 = pPeleFWIMData->transactionLabel << kPeleAsynchTLabelPhase;
- data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
- data1 |= kFWTCodeWriteBlock << kPelePacketTCodePhase;
-
- // Write packet address.
- data2 = pFWIMAsynchCommandParams->addressHi;
- data3 = pFWIMAsynchCommandParams->addressLo;
-
- // Write request length.
- data4 = pFWIMAsynchCommandParams->length << kPeleAsynchDataLengthPhase;
-
- PeleFWIMWriteAT (pPeleFWIMData, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
- pFWIMAsynchCommandParams->length,
- (UInt32 *) pFWIMAsynchCommandParams->buffer);
- }
- }
-
- // Complete command on error.
- if (status != noErr)
- {
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
- status);
- }
- else
- {
- // We no longer take TxRdy interrupt, instead, the status should already be waiting for us.
- //zzz We probably should take an interrupt. Other transmit stuff (like isoch) could
- //zzz be blocking this transmission for relatively long periods of time.
- PeleFWIMAckSecondaryInterruptHandler
- (pPeleFWIMData, &(pPeleFWIMData->asynchXmitDMA[kAsynchTxDataDMA]));
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMWriteResponse
- //
- // This proc sends a write response packet.
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus PeleFWIMWriteResponse(
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- UInt32 data1, data2;
- UInt32 transactionLabel;
- UInt32 responseCode;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMResponseCommand =
- (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
-
- // Check if generation is up to date.
- if ((!(pPeleFWIMData->generationValid)) ||
- (pFWIMAsynchResponseCommandParams->generation != pPeleFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
-
- // Write write response to ATF.
- if (status == noErr)
- {
- // Compute transaction label and response code.
- transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
- kFWTransactionDescriptorTLabel) >>
- kFWTransactionDescriptorTLabelPhase;
- responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
- kFWResponseDataRCode) >>
- kFWResponseDataRCodePhase;
-
- // packet control header goes in quad 1
- data1 = kFWTCodeWriteResponse << kPelePacketTCodePhase;
- data1 |= transactionLabel << kPeleAsynchTLabelPhase;
- data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
-
- // packet destination node ID and response code go in quad 2
- data2 = pFWIMAsynchResponseCommandParams->destinationID << kPeleAsynchSourceIDPhase;
- data2 |= responseCode << kPeleAsynchRCodePhase;
-
- PeleFWIMWriteAT (pPeleFWIMData, pFWIMAsynchResponseCommandParams->speed, 3, data1, data2, 0, 0, 0, 0);
- }
-
- // Complete command on error.
- //zzz assume success for now. should check ack code for success.
- //zzz if (status != noErr)
- {
- pPeleFWIMData->pPendingFWIMResponseCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
- status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMLock
- //
- // This proc performs a lock transaction on the FireWire bus.
- //zzz what if timer goes off before request goes out??? A: Execute this proc
- //zzz at secondary interrupt level
- //zzz check length against maximum packet size
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus PeleFWIMLock(
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- UInt32 data1, data2, data3, data4;
- AbsoluteTime timeoutAbsolute;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMLock");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Check if generation is up to date.
- if ((!(pPeleFWIMData->generationValid)) ||
- (pFWIMAsynchCommandParams->generation != pPeleFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
-
- // Set a timeout timer.
- if (status == noErr)
- {
- timeoutAbsolute =
- AddAbsoluteToAbsolute (UpTime (),
- DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
- status = SetInterruptTimer
- (&timeoutAbsolute, PeleFWIMLockRequestTimeoutHandler,
- pFWIMAsynchCommandParams,
- &(pPeleFWIMData->requestTimeoutTimerID));
- if (status == noErr)
- pPeleFWIMData->requestTimeoutTimerSet = true;
- }
-
- // send lock request.
- if (status == noErr)
- {
- pPeleFWIMData->transactionLabel =
- (pPeleFWIMData->transactionLabel + 1) & 0x3F;
- pPeleFWIMData->tCode = kFWTCodeLock;
-
- // Prepare packet control header for block transaction.
- data1 = (pPeleFWIMData->transactionLabel << kPeleAsynchTLabelPhase);
- data1 |= (kPeleAsynchNew << kPeleAsynchRtPhase);
- data1 |= (kFWTCodeLock << kPelePacketTCodePhase);
-
- // our ID and the target address.
- data2 = pFWIMAsynchCommandParams->addressHi;
- data3 = pFWIMAsynchCommandParams->addressLo;
-
- // request length and extended tCode.
- data4 = pFWIMAsynchCommandParams->length << kPeleAsynchDataLengthPhase;
- data4 |=
- (pFWIMAsynchCommandParams->extendedTCode & kPeleAsynchExtendedTCode) <<
- kPeleAsynchExtendedTCodePhase;
-
- PeleFWIMWriteAT(pPeleFWIMData, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
- pFWIMAsynchCommandParams->length,
- (UInt32 *) pFWIMAsynchCommandParams->buffer);
- }
-
- // Complete command on error.
- if (status != noErr)
- {
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
- status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMLockResponse
- //
- // This proc sends a lock response packet.
- //zzz should be set up to get acknowledgement
- //
-
- static OSStatus PeleFWIMLockResponse(
- FWIMAsynchResponseCommandParamsPtr
- pFWIMAsynchResponseCommandParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- UInt32 data1, data2, data4;
- UInt32 transactionLabel;
- UInt32 responseCode;
- OSStatus status = noErr;
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMResponseCommand =
- (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
-
- // Check if generation is up to date.
- if ((!(pPeleFWIMData->generationValid)) ||
- (pFWIMAsynchResponseCommandParams->generation != pPeleFWIMData->generation))
- {
- status = busReconfiguredErr;
- }
-
- // Write lock response to ATF.
- if (status == noErr)
- {
- // Compute transaction label and response code.
- transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
- kFWTransactionDescriptorTLabel) >>
- kFWTransactionDescriptorTLabelPhase;
- responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
- kFWResponseDataRCode) >>
- kFWResponseDataRCodePhase;
-
- // packet control header goes in quad 1
- data1 = transactionLabel << kPeleAsynchTLabelPhase;
- data1 |= kPeleAsynchNew << kPeleAsynchRtPhase;
- data1 |= kFWTCodeLockResponse << kPelePacketTCodePhase;
-
- // packet destination node ID and response code go in quad 2
- data2 = pFWIMAsynchResponseCommandParams->destinationID << kPeleAsynchSourceIDPhase;
- data2 |= responseCode << kPeleAsynchRCodePhase;
-
- data4 = pFWIMAsynchResponseCommandParams->length << kPeleAsynchDataLengthPhase;
- data4 |=
- (pFWIMAsynchResponseCommandParams->extendedTCode & kPeleAsynchExtendedTCode) <<
- kPeleAsynchExtendedTCodePhase;
-
- PeleFWIMWriteAT (pPeleFWIMData, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
- }
-
- // Complete command on error.
- //zzz assume success for now. should check ack code for success.
- //zzz if (status != noErr)
- {
- pPeleFWIMData->pPendingFWIMResponseCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
- status);
- }
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMIsCompilableDCLProgram
- //
- // This routine determines if the given DCL program is compilable.
- //zzz a table and range check may be faster.
- //zzz should do better checking.
- //zzz maybe we should make this determination in a first pass compilation.
- //
-
- static Boolean PeleFWIMIsCompilableDCLProgram(
- DCLProgramID dclProgramID)
- {
- DCLCommandPtr pDCLCommand;
- Boolean isCompilable = true;
- UInt32 opcode;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMIsCompilableDCLProgram...");
-
- // Get first DCL in program.
- status = FWGetDCLProgramStart (dclProgramID, &pDCLCommand);
- if (status != noErr)
- isCompilable = false;
-
- // Check each DCL in program.
- while ((isCompilable) && (pDCLCommand != nil))
- {
- opcode = pDCLCommand->opcode;
- opcode &= ~kFWDCLOpDynamicFlag; // We can compile dynamic opcodes.
- switch (opcode)
- {
- case kDCLReceivePacketStartOp :
- break;
-
- case kDCLReceivePacketOp :
- break;
-
- case kDCLSendPacketStartOp :
- break;
-
- case kDCLSendPacketWithHeaderStartOp :
- break;
-
- case kDCLSendPacketOp :
- break;
-
- case kDCLCallProcOp :
- break;
-
- case kDCLJumpOp :
- break;
-
- case kDCLLabelOp :
- break;
-
- case kDCLSetTagSyncBitsOp :
- break;
-
- case kDCLUpdateDCLListOp :
- break;
-
- case kDCLTimeStampOp :
- break;
-
- default :
- isCompilable = false;
- break;
- }
-
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
-
- sprintf (debugStr, " isCompilable = %ld", (long) isCompilable);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- return isCompilable;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMPrepareDCLProgramMemory
- //
- // This routine prepares all buffers used within a DCL program for physical
- // I/O, and determines the physical addresses. dclList is the entire program.
- //
-
- static OSStatus PeleFWIMPrepareDCLProgramMemory(
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData,
- DCLCommandPtr dclList,
- UInt32 dclListLength)
- {
- DCLCommandPtr pDCL;
- DCLTransferPacketPtr pDCLTransferPacket;
- IOPreparationTable *ioPrep;
- PhysicalAddress *physAddrs; // should be PhysicalMappingTablePtr
- AddressRangeTablePtr rangeTable;
- UInt32 pageSize, pageShift, pageMask, tmp;
- UInt32 pageCount, bufferCount;
- AbsoluteTime timeNow;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMPrepareDCLProgramMemory");
-
- ioPrep = &pPeleDCLCompilerEngineData->ioPrep;
- pageSize = GetLogicalPageSize ();
- pageShift = 0;
- for (tmp = pageSize; tmp = tmp >> 1; pageShift++); // Sorry...
- pageMask = ~(pageSize - 1);
-
- // This is gross too. Make sure we don't use stale data in lookups.
- timeNow = UpTime ();
- pPeleDCLCompilerEngineData->engineGeneration = AbsoluteToDuration (timeNow);
-
- // We will need to allocate a page table. We don't know how big it needs
- // to be, but we can wait until just before we PrepareMemoryForIO to do
- // the allocation (by then we'll know)
-
- // We need to allocate a range/length table. We fill that in before we
- // call PrepareMemoryForIO, and it has to be linear, so we have to allocate
- // it all at once. We need one entry for each buffer in the program.
- // That's why we take a parameter indicating the program length.
- // Note if we ever allow scatter/gather buffers in a DCL program, this
- // will have to change.
-
- // We assumed (in PeleFWIMCompileDCLProgram) that each DCL contained a buffer.
- // Some of them are branches, etc, so an optimization would be to count more
- // precisely and save a little memory.
-
- // Allocate space for rangeTable
- if (status == noErr)
- {
- rangeTable = (AddressRangeTablePtr)
- PoolAllocateResident (dclListLength * sizeof (AddressRange), false);
- if (!rangeTable) status = memFullErr;
- ioPrep->rangeInfo.multipleRanges.entryCount = 0;
- // move this below, use local copy
- ioPrep->rangeInfo.multipleRanges.rangeTable = rangeTable;
- }
-
- // Gather information about buffers/pointers
- if (status == noErr)
- {
- pDCL = dclList;
- bufferCount = 0; // shadow of ioPrep->rangeInfo.multipleRanges.entryCount
- pageCount = 0; // count page table size we will need to allocate
-
- while (pDCL != nil)
- {
- switch (pDCL->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLReceivePacketStartOp :
- case kDCLReceivePacketOp :
- case kDCLSendPacketStartOp :
- case kDCLSendPacketWithHeaderStartOp :
- case kDCLSendPacketOp :
-
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCL;
- rangeTable[bufferCount].base = (void *) pDCLTransferPacket->buffer;
- rangeTable[bufferCount].length = pDCLTransferPacket->size;
- bufferCount++;
-
- // buffer + size - 1 is addr of last byte in buffer.
- // shift that right by pageShift to get page index of end.
- // subtract first page index and add one to get total page count.
-
- pageCount += // (last page - first page) + 1
- ((((((UInt32) (pDCLTransferPacket->buffer)) + pDCLTransferPacket->size) - 1) >> pageShift) -
- (((UInt32) (pDCLTransferPacket->buffer)) >> pageShift) + 1);
- break;
-
- default : //No buffer or pointer - nothing to do
- break;
- }
-
- pDCL = pDCL->pNextDCLCommand;
- }
- }
-
- // Allocate space for page table
- if (status == noErr)
- {
- physAddrs = PoolAllocateResident (pageCount * sizeof (PhysicalAddress), false);
- if (!physAddrs)
- {
- status = memFullErr;
- PoolDeallocate ((Ptr) rangeTable);
- }
- pPeleDCLCompilerEngineData->physAddrs = physAddrs;
- }
-
- // Prepare memory for I/O
- if (status == noErr)
- {
- ioPrep->options = kIOMultipleRanges | kIOLogicalRanges |
- kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = pageCount; // we counted exactly
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = physAddrs; // return list of phys addrs
- ioPrep->rangeInfo.multipleRanges.entryCount = bufferCount;
-
- // CheckpointIO is in _PeleFWIMReleaseIsochPort
- status = PrepareMemoryForIO (ioPrep);
- if (status != noErr)
- {
- ioPrep->mappingEntryCount = -1; // prevents CheckpointIO, kind of a hack
- PoolDeallocate ((Ptr) rangeTable);
- PoolDeallocate ((Ptr) physAddrs);
-
- sprintf (debugStr, "DCL data PrepMemIO status %ld page count %ld",
- (long) status,
- (long) pageCount);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDataMapBufferToPhysical
- //
- // This routine looks up physical addresses for buffers/pointers.
- // Fills in the passed page table, returns page count (0 if not found)
-
- static UInt32 PeleFWIMDataMapToPhysical (
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData,
- Ptr pBuffer,
- UInt32 size,
- PhysicalMappingTablePtr returnTable)
- {
- UInt32 pageCount = 0, lookCount = 0;
- static UInt32 rangeLook = 0, pageLook = 0;
- static UInt32 pageSize = 0, pageShift = 0;
- static UInt32 cacheEngineGeneration = 0;
- IOPreparationTable *ioPrep = &pPeleDCLCompilerEngineData->ioPrep;
- AddressRangeTablePtr try;
- if (!pageSize)
- {
- UInt32 tmp;
- pageSize = GetLogicalPageSize ();
- for (tmp = pageSize; tmp = tmp >> 1; pageShift++); // Sorry...
- }
-
- // Look up phys addrs in our prepared table
- // Return in provided page table
-
- // Start lookup from last known point, if we build in order, lookup is fast
- // Strictly speaking, rangeLook and pageLook should be static to the
- // engine data, not the whole FWIM, but I don't think we can compile more
- // than one DCL program at a time anyway.
- //
- // Perhaps more importantly, they should be reset if we've rebuilt the ioPrep,
- // because they may be off the end or otherwise inaccurate.
- //
- // I'm not sure this (optimization) works - it still seems sluggish.
-
- if (cacheEngineGeneration != pPeleDCLCompilerEngineData->engineGeneration)
- {
- cacheEngineGeneration = pPeleDCLCompilerEngineData->engineGeneration;
- rangeLook = 0;
- pageLook = 0;
- }
-
- // Repeat until we find it or run out of places to look
-
- while ((lookCount < ioPrep->rangeInfo.multipleRanges.entryCount) && (!pageCount))
- {
- try = &ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook];
-
- // pageCount is number of physAddr entries used by this range
- // either copy them (found) or skip over them (not found)
-
- pageCount = 1 + (((UInt32) try->base + try->length - 1) >> pageShift) -
- ((UInt32) try->base >> pageShift);
-
- // require exact match
- if ((void *) pBuffer == ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook].base)
- {
- // Found pages we want. Copy page table.
- BlockCopy (&ioPrep->physicalMapping[pageLook],
- returnTable,
- pageCount * sizeof (PhysicalAddress));
- pageLook += pageCount;
- }
- else
- {
- // These aren't the pages we're looking for. Skip forward.
- pageLook += pageCount;
- pageCount = 0;
- }
-
- lookCount++;
- rangeLook++;
- if (rangeLook == ioPrep->rangeInfo.multipleRanges.entryCount)
- {
- rangeLook = 0;
- pageLook = 0;
- }
- }
-
- if (!pageCount)
- FWDebugStr ((ConstStr255Param) "\pFailed to find buffer!");
-
- return pageCount;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMCompileDCLProgram
- //
- // This routine compiles the given DCL program into a PCL program.
- //zzz rename this
- //zzz need to set proper speed.
- //
-
- static OSStatus PeleFWIMCompileDCLProgram(
- PeleFWIMDataPtr pPeleFWIMData,
- DCLProgramID dclProgramID,
- UInt32 dmaChannelNum,
- UInt32 channelNum,
- UInt32 speed)
- {
- PeleDMABuildStatePtr pPeleDMABuildState = nil;
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData = nil;
- DCLCommandPtr pDCLCommand,
- dclList;
- // DCLLabel waitLoopDCLLabel,
- // transmitDCLLabel;
- // DCLCommand waitLoopDCLCommand;
- PeleDMAPtr pStartDMA;
- UInt32 startEvent,
- startEventState,
- startEventStateMask;
- UInt32 dclListLength;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMCompileDCLProgram");
-
- // Create DCL engine data record.
- pPeleDCLCompilerEngineData = (PeleDCLCompilerEngineDataPtr)
- PoolAllocateResident (sizeof (PeleDCLCompilerEngineData), true);
- if (pPeleDCLCompilerEngineData == nil)
- status = memFullErr;
-
- // Initialize interrupt queue.
- if (status == noErr)
- pPeleFWIMData->pDCLInterruptTail[dmaChannelNum] = nil;
-
- // Set compiler notification proc.
- if (status == noErr)
- {
- status = FWSetDCLProgramCompilerNotificationProc
- (dclProgramID, PeleFWIMDCLCompilerNotification);
- }
-
- // Get DCL list from program.
- //zzz should check for error.
- if (status == noErr)
- status = FWGetDCLProgramStart (dclProgramID, &dclList);
-
- // Count DCLs.
- if (status == noErr)
- {
- pDCLCommand = dclList;
- dclListLength = 0;
- while (pDCLCommand != nil)
- {
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- dclListLength++;
- }
- }
-
- // Allocate compiler data structures for all DCLs
- if (status == noErr)
- {
- pPeleDCLCompilerDCLData =
- PoolAllocateResident (dclListLength * sizeof (PeleDCLCompilerDCLData), true);
- if (pPeleDCLCompilerDCLData == nil)
- {
- status = memFullErr;
- }
- else
- {
- pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData = pPeleDCLCompilerDCLData;
- // Assign compiler data storage to each DCL
- pDCLCommand = dclList;
- while (pDCLCommand != nil)
- {
- pDCLCommand->compilerData = (UInt32) pPeleDCLCompilerDCLData;
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- pPeleDCLCompilerDCLData++;
- }
- }
- }
-
- // The plan is to, before compiling, scan the program to locate all data
- // buffers. Then we'll prepare VM mappings for them all at once. Then
- // during compilation we can look up the logical->physical mappings.
- //
- // A complication is that we may receive notification that a running
- // program has had its buffers changed. We get a list of changes. In
- // that case we need to prepare the new buffers for DMA and change the
- // pointers in the PCLs, possibly expanding PCLs if there are more
- // page crossings than before. (or maybe not)
- //
- // When we update buffers, some may be unchanged, so we can't clear the
- // original PrepareMemoryForIO. Buffers can be updated repeatedly, and
- // we could pile up unlimited ioPrep structures. So we use a brute-force
- // solution (NYI) and redo the *entire* ioPrep, not just the changed buffers.
- // Then we can free (CheckpointIO) the original one, and all live buffers
- // are still covered. (There is room for optimizations in that process.)
- //
- // The first time we prepare memory, we have the luxury that the program
- // is not running. When we do updates, the program *is* running. But maybe
- // we can use the same code both times, somehow.
-
- if (status == noErr)
- status = PeleFWIMPrepareDCLProgramMemory (pPeleDCLCompilerEngineData,
- dclList,
- dclListLength);
-
- // Start writing our DBDMA program.
- if (status == noErr)
- {
- status = PeleFWIMDMAStart (pPeleFWIMData, &pPeleDMABuildState, &pStartDMA);
-
- if (status == noErr)
- {
- pPeleDMABuildState->pPeleDCLCompilerEngineData = pPeleDCLCompilerEngineData;
- pPeleDMABuildState->dmaChannelNum = dmaChannelNum;
- pPeleDMABuildState->isochChannelNum = channelNum;
- }
- }
-
- // Check if there's a start event for the cycle count.
- if (status == noErr)
- {
- status = FWGetDCLProgramStartEvent
- (dclProgramID, &startEvent, &startEventState, &startEventStateMask);
- }
- if ((status == noErr) && (startEvent == kFWDCLCycleEvent))
- {//zzz need to deal with mask including upper 16 bits
-
- // This is all Lynx based. Replace with Pele start-on-cycle hardware mechanism
- // In Lynx, we match on bits 12-15 (low 4 of cycle number). But Pele always matches
- // all 20 bits of cycle number + cycle second.
- #if 0
- // Create some DCLs to wait for cycle event.
- waitLoopDCLLabel.pNextDCLCommand = &waitLoopDCLCommand;
- waitLoopDCLLabel.compilerData = nil;
- waitLoopDCLLabel.opcode = kDCLLabelOp;
-
- waitLoopDCLCommand.pNextDCLCommand = (DCLCommandPtr) &transmitDCLLabel;
- waitLoopDCLCommand.compilerData = nil;
- waitLoopDCLCommand.opcode = kDCLInvalidOp;
-
- transmitDCLLabel.pNextDCLCommand = dclList;
- transmitDCLLabel.compilerData = nil;
- transmitDCLLabel.opcode = kDCLLabelOp;
-
- // Add wait loop label.
- status =
- PeleFWIMAddLabelDCL (pPeleDMABuildState, (DCLCommandPtr) &waitLoopDCLLabel);
-
- // Add a wait for cycle count commands.
- // We must set up to start filling the cycle before the cycle we want the packet
- // to go out on.
- //zzz setting a compare for startEventState - (1 << 12) will only work right
- //zzz when bit 12 is set in the mask.
- if (status == noErr)
- {
- //This address is already physical, no translation needed
- status =
- PeleFWIMPCLLoadTemp (pPeleDMABuildState,
- (Ptr) &(pPeleFWIMData->pPeleRegisters->cycleTimer));
- }
- if (status == noErr)
- {
- status = PeleFWIMPCLCompareTemp16WithMask (pPeleDMABuildState,
- startEventState - (1 << 12),
- startEventStateMask);
- }
- if (status == noErr)
- status = PeleFWIMPCLBranchIfEqual (pPeleDMABuildState, &transmitDCLLabel);
- if (status == noErr)
- status = PeleFWIMPCLJump (pPeleDMABuildState, &waitLoopDCLLabel, nil);
-
- // Add transmit label.
- if (status == noErr)
- {
- status = PeleFWIMAddLabelDCL (pPeleDMABuildState,
- (DCLCommandPtr) &transmitDCLLabel);
-
- // Set ready register to 1 after we exit the wait loop.
- // We'll stop transmitting if we find ready has been zeroed.
-
- status = PeleFWIMPCLStore1 (pPeleDMABuildState,
- (Ptr) &(pPeleFWIMData->pPeleRegisters->dmaChannel[kIsochTransmitDMA].ready));
- }
- #endif
- }
-
- // Process all DCLs.
- pDCLCommand = dclList;
- while ((pDCLCommand != nil) && (status == noErr))
- {
- status = PeleFWIMAddDCL (pPeleDMABuildState, pDCLCommand);
- pDCLCommand = pDCLCommand->pNextDCLCommand;
- }
-
- if (status == noErr)
- status = PeleFWIMAddStopDCL (pPeleDMABuildState);
-
- // Fill in DCL engine data record.
- if (status == noErr)
- {
- pPeleDCLCompilerEngineData->pStartDMA = pStartDMA;
- pPeleDCLCompilerEngineData->pPeleDMAPoolDataList =
- pPeleDMABuildState->pPeleDMAPoolDataList;
- pPeleDCLCompilerEngineData->pPeleFWIMData = pPeleFWIMData;
- }
-
- // Save engine data.
- if (status == noErr)
- {
- status = FWSetDCLProgramEngineData (dclProgramID,
- (UInt32) pPeleDCLCompilerEngineData);
- }
-
- // Clean up on error.
- if (status != noErr)
- {
- // Deallocate PCL pools.
- if (pPeleDMABuildState != nil)
- if (pPeleDMABuildState->pPeleDMAPoolDataList != nil)
- PeleFWIMDeallocateDMAPools (pPeleDMABuildState->pPeleDMAPoolDataList);
-
- // Deallocate compiler DCL data.
- if (pPeleDCLCompilerEngineData != nil)
- if (pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData != nil)
- PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData);
-
- // Deallocate engine data.
- if (pPeleDCLCompilerEngineData != nil)
- PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData);
- }
-
- // Clean up.
- if (pPeleDMABuildState != nil)
- PoolDeallocate ((Ptr) pPeleDMABuildState);
-
- sprintf (debugStr, " ...PeleFWIMCompileDCLProgram returns %ld", (long) status);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddDCL
- //
- // This proc adds the given DCL.
- //
-
- static OSStatus PeleFWIMAddDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- UInt32 opcode;
- OSStatus status = noErr;
-
- // Dispatch off of opcode.
- opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
-
- // sprintf (debugStr, "PeleFWIMAddDCL %ld / %ld", (long) opcode, (long) pDCLCommand->opcode);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
-
- switch (opcode)
- {
- case kDCLReceivePacketStartOp :
- status = PeleFWIMAddReceivePacketStartDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLReceivePacketOp :
- status = PeleFWIMAddReceivePacketDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLSendPacketStartOp :
- status = PeleFWIMAddSendPacketStartDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLSendPacketWithHeaderStartOp :
- status = PeleFWIMAddSendPacketWithHeaderStartDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLSendPacketOp :
- status = PeleFWIMAddSendPacketDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLCallProcOp :
- status = PeleFWIMAddCallProcDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLJumpOp :
- status = PeleFWIMAddJumpDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLLabelOp :
- status = PeleFWIMAddLabelDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLSetTagSyncBitsOp :
- status = PeleFWIMAddSetTagSyncBitsDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLUpdateDCLListOp :
- status = PeleFWIMAddUpdateDCLListDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- case kDCLTimeStampOp :
- status = PeleFWIMAddTimeStampDCL (pPeleDMABuildState, pDCLCommand);
- break;
-
- default : //zzz what can we do?
- break;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddReceivePacketStartDCL
- //
- // This proc adds a receive packet start DCL.
- //zzz need to be able to specify speed.
- //
-
- static OSStatus PeleFWIMAddReceivePacketStartDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLTransferPacketPtr pDCLTransferPacket;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- PeleDMAPtr pDMA;
- PhysicalAddress pDMAPhys;
- PhysicalAddress physAddrs[4]; // enough for 800 mbits
- UInt32 pageCount;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
-
- // Allocate new descriptor.
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
-
- // Get physical addresses.
- pageCount = PeleFWIMDataMapToPhysical (pPeleDMABuildState->pPeleDCLCompilerEngineData,
- pDCLTransferPacket->buffer,
- pDCLTransferPacket->size,
- physAddrs);
-
- // For now, pageCount can be at most 2. 3 pages would be 4098 bytes, not possible at 200mbps.
- // We can handle 2 only if contiguous.
- if (pageCount == 2)
- {
- // Hack - know page size is 4096 (2^^12)
- if ((((UInt32) (physAddrs[0])) >> 12) + 1 != (((UInt32) (physAddrs[1])) >> 12))
- {
- sprintf (debugStr, "Isoch receive spans 2 pages, not contig [%08lx & %08lx]",
- (long) physAddrs[0],
- (long) physAddrs[1]);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- status = -1;
- }
- }
-
- // Set up descriptor.
- if (status == noErr)
- {
- // Unlike Lynx, Pele does not receive the 1394 isoch packet header. It gets
- // stripped out in hardware. But the API requires it to be put in the target
- // buffer. So, push the buffer forward 4 bytes, and we'll fake the header later
- // during the update.
-
- pDMA->operation =
- EndianSwap32Bit (kPeleINPUT_LAST | // Entire packet in one buffer
- kPeleKEY_STREAM0 | // Only STREAM implemented
- kPeleIntNever | // No Interrupt
- kPeleBranchAlways | // Branch to next descriptor
- kPeleWaitNever | // No wait
- (pDCLTransferPacket->size - 4)); // reqCount
- pDMA->address = EndianSwap32Bit (((UInt32) physAddrs[0]) + 4);
- pDMA->cmdDep = EndianSwapImm32Bit (0); // branch address - will be filled in later.
- pDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
- }
-
- // Link previous descriptor.
- if ((status == noErr) && pPeleDMABuildState->pLastBranch)
- {
- *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
- }
-
- // Update build state.
- if (status == noErr)
- {
- // Our new descriptor doesn't yet have a branch address. Here's where it goes:
- pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDMA->cmdDep);
- }
-
- // Return results.
- if (status == noErr)
- {
- pPeleDCLCompilerDCLData->pDMA = pDMA;
- pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
- }
- else
- {
- pPeleDCLCompilerDCLData->pDMA = nil;
- pPeleDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddReceivePacketDCL
- //
- // This proc adds a receive packet DCL.
- //
-
- static OSStatus PeleFWIMAddReceivePacketDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMAddReceivePacketDCL is not supported");
- return -1;
- #if 0
- DCLTransferPacketPtr pDCLTransferPacket;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- OSStatus status = noErr;
-
- There is just no good general-purpose way to compile this opcode if the packet
- sizes are unpredictable and the buffers sent to us are not contiguous, because
- Pele can't deal with that. At best, we could check for contiguous buffers and
- merge them, issuing a paramErr otherwise. The only other way out is to allocate
- our own big buffer in the FWIM and then copy out the results during the Update.
- That uses a lot of memory and CPU and seems kind of pointless.
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
-
- return status;
- #endif
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddSendPacketStartDCL
- //
- // This proc adds a send packet start DCL.
- // It also compiles the following sendPacketOp DCLs
- //zzz need to be able to specify speed.
- //
-
- static OSStatus PeleFWIMAddSendPacketStartDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLTransferPacketPtr pDCLTransferPacket,
- pDCLTransferPacketStart;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- UInt32 packetSize, packetPageCount, doPage;
- PhysicalAddress physTable[20]; // what is a realistic limit?
- UInt32 sizeTable[20]; // ???
- UInt32 pageCount;//, pageSize, firstPageSize;
- PeleDMAPtr pDMA, pDoDMA;
- PhysicalAddress pDMAPhys;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTransferPacketStart = (DCLTransferPacketPtr) pDCLCommand;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
-
- // First scan any SendPacketOp DCLs that follow this SendPacketStartOp DCL.
- // They will all combine with this one to send a single packet. Find out
- // all of the physical addresses and data sizes that we will need, including
- // a count of descriptors.
-
- pDCLTransferPacket = pDCLTransferPacketStart;
- packetSize = 0;
- packetPageCount = 0;
- do
- {
- packetSize += pDCLTransferPacket->size;
- pageCount = PeleFWIMDataMapToPhysical (pPeleDMABuildState->pPeleDCLCompilerEngineData,
- pDCLTransferPacket->buffer,
- pDCLTransferPacket->size,
- &(physTable[packetPageCount]));
-
- if (pageCount == 1)
- {
- sizeTable[packetPageCount] = pDCLTransferPacket->size;
- }
- else if (pageCount == 2)
- {
- // Page size hardwired to 4096 / 0x1000 for now
- sizeTable[packetPageCount] = 0x1000 - ((UInt32) physTable[packetPageCount] & 0x0fff);
- sizeTable[packetPageCount + 1] = pDCLTransferPacket->size - sizeTable[packetPageCount];
- }
- else status = -1; //zzz should handle more than 2 pages for 400/800 mbps.
-
- packetPageCount += pageCount;
-
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
-
- if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) != kDCLSendPacketOp)
- {
- pDCLTransferPacket = nil;
- }
- } while (pDCLTransferPacket != nil);
-
- // Allocate new descriptor.
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, packetPageCount + 1);
-
- pDoDMA = pDMA;
- // Because Pele synthesizes the packet header for us, it can't take a stream of
- // OUTPUT_MOREs followed by an OUTPUT_LAST and form up a single isoch packet.
- // If the packet is bigger than the FIFO, Pele would have to send the header,
- // with the packet length in it, before it had ever seen the descriptor for the
- // final part of the packet. So Pele would not know how big the packet was going
- // to be until it was too late.
-
- // Lynx requires us to form the header in software, where we know how big the
- // packet is going to be, so Lynx doesn't have this difficulty.
-
- // So as a tremendous hack, use the rateMode isochronous transmit, and change "I"
- // prior to every packet. This forces Pele to send a packet of size I using as
- // many descriptors as needed, which we will provide.
-
- // Write first descriptor to STORE_QUAD the packet length into I+n/d
- // zzz shouldn't hardwire to itaControl.
- if (status == noErr)
- {
- pDoDMA->operation =
- EndianSwap32Bit (kPeleSTORE_QUAD | // Write I+n/d register
- kPeleKEY_SYSTEM | // Works for PCI registers too
- kPeleIntNever | // No Interrupt
- kPeleWaitNever | // No wait
- 4); // reqCount
- pDoDMA->address = EndianSwap32Bit ((UInt32)
- &(pPeleDMABuildState->pPeleFWIMData->pPeleRegisters->itaControl.bandwidthControl));
- pDoDMA->cmdDep = EndianSwap32Bit (packetSize << 16); // data.
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- pDoDMA++;
- }
-
- // Set up payload descriptors.
- if (status == noErr)
- {
- for (doPage = 0; doPage < packetPageCount; doPage++)
- {
- pDoDMA->operation =
- EndianSwap32Bit (kPeleKEY_STREAM0 | // Only STREAM implemented
- kPeleIntNever | // No Interrupt
- kPeleBranchNever | // Go on to next descriptor
- kPeleWaitNever | // No wait
- sizeTable[doPage]); // reqCount
-
- // Doesn't actually matter if we use MORE or LAST, but pretend it does:
-
- if (doPage + 1 == packetPageCount)
- pDoDMA->operation |= EndianSwapImm32Bit (kPeleOUTPUT_LAST);
- else pDoDMA->operation |= EndianSwapImm32Bit (kPeleOUTPUT_MORE);
- pDoDMA->address = EndianSwap32Bit ((UInt32) physTable[doPage]);
- pDoDMA->cmdDep = EndianSwapImm32Bit (0); // branch address - may be filled in later.
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- pDoDMA++;
- }
- pDoDMA--; // point to final DMA
- pDoDMA->operation |= EndianSwapImm32Bit (kPeleBranchAlways);
- }
-
- // Link previous descriptor.
- if ((status == noErr) && pPeleDMABuildState->pLastBranch)
- {
- *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
- }
-
- // Update build state.
- if (status == noErr)
- {
- // Our last descriptor doesn't yet have a branch address. Here's where it goes:
- pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDoDMA->cmdDep);
- }
-
- // Return results.
- //zzz should fill in CompilerDCLData for SendPacketOps we compiled.
- // but I don't think it ever gets used, unless we update buffers (NYI anyway)
- if (status == noErr)
- {
- pPeleDCLCompilerDCLData->pDMA = pDMA;
- pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
- }
- else
- {
- pPeleDCLCompilerDCLData->pDMA = nil;
- pPeleDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddSendPacketWithHeaderStartDCL
- //
- // This proc adds a send packet with header start DCL.
- //zzz need to be able to specify speed.
- //
-
- static OSStatus PeleFWIMAddSendPacketWithHeaderStartDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- //zzz I think this could be a special case of SendPacketStart, where we examine the header
- // and write a STORE_QUAD to configure the isoch transmitter accordingly before each packet.
- // We'll have to re-examine the header after each Update.
-
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMAddSendPacketWithHeaderStartDCL is not supported");
- return -1;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddSendPacketDCL
- //
- // This proc adds a send packet DCL.
- // zzz In case it doesn't get documented anywhere else, the DCL "SendPacket"
- // actually means send *part* of a packet. All consecutive SendPackets will
- // be merged together with the previous SendPacketStart, to form a single packet.
- // The same is true of ReceivePacket.
- //
- // There's nothing to do here, because we already processed this when we saw
- // the preceeding SendPacketStartOp.
-
- static OSStatus PeleFWIMAddSendPacketDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- //zzz rename to AddInterruptDMA or something, call directly.
- // PeleFWIMAddCallProcDCL
- //
- // This proc compiles a call proc DCL into three descriptors.
- //
-
- static OSStatus PeleFWIMAddCallProcDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- PeleDMAPtr pDMA, pDoDMA;
- PhysicalAddress pDMAPhys;
- PeleFWIMDataPtr pPeleFWIMData, physPeleFWIMData;
- UInt32 dmaChannelNum;
- OSStatus status = noErr;
-
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
-
- // Get Pele FWIM data.
- pPeleFWIMData = pPeleDMABuildState->pPeleFWIMData;
- physPeleFWIMData = (PeleFWIMDataPtr) pPeleFWIMData->fwimDataPhys;
- dmaChannelNum = pPeleDMABuildState->dmaChannelNum;
-
- // Allocate new descriptors.
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 3);
-
- // Set up descriptors.
- if (status == noErr)
- {
- pDoDMA = pDMA;
-
- // Load current interrupt link and stash it in this descriptor
-
- pDoDMA->operation =
- EndianSwapImm32Bit (kPeleLOAD_QUAD | // Load current interrupt queue
- kPeleKEY_SYSTEM |
- kPeleIntNever | // No interrupt
- kPeleWaitNever | // No wait
- 4); // reqCount
- pDoDMA->address =
- EndianSwap32Bit ((UInt32) &(physPeleFWIMData->pDCLInterruptTail[dmaChannelNum]));
- pDoDMA->cmdDep = EndianSwapImm32Bit (0); // Will be filled by load.
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- pDoDMA++;
-
- // Store our DCL pointer into the tail pointer
-
- pDoDMA->operation =
- EndianSwapImm32Bit (kPeleSTORE_QUAD | // Store ourselves at queue tail
- kPeleKEY_SYSTEM |
- kPeleIntNever | // No interrupt
- kPeleWaitNever | // No wait
- 4); // reqCount
- pDoDMA->address =
- EndianSwap32Bit ((UInt32) &(physPeleFWIMData->pDCLInterruptTail[dmaChannelNum]));
- pDoDMA->cmdDep = EndianSwap32Bit ((UInt32) pDCLCommand); // value to store.
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- pDoDMA++;
-
- // LOAD_QUAD and STORE_QUAD don't have branch addresses, so do a NOP and branch.
-
- pDoDMA->operation =
- EndianSwapImm32Bit (kPeleNOP_CMD | // Do nothing
- kPeleIntAlways | // ... except Interrupt
- kPeleBranchAlways | // ... and branch to next descriptor
- kPeleWaitNever); // No wait
- pDoDMA->address = EndianSwapImm32Bit (0);
- pDoDMA->cmdDep = EndianSwapImm32Bit (0); // branch address - will be filled in later.
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
- }
-
- // Link previous descriptor.
- if ((status == noErr) && pPeleDMABuildState->pLastBranch)
- {
- *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
- }
-
- // Update build state.
- if (status == noErr)
- {
- // Our new descriptor doesn't yet have a branch address. Here's where it goes:
- pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDoDMA->cmdDep);
- }
-
- // Return results.
- if (status == noErr)
- {
- pPeleDCLCompilerDCLData->pDMA = pDMA;
- pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
- }
- else
- {
- pPeleDCLCompilerDCLData->pDMA = nil;
- pPeleDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddJumpDCL
- //
- // This proc adds a jump DCL.
- //
-
- static OSStatus PeleFWIMAddJumpDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- PeleDMAPtr pDMA;
- PhysicalAddress pDMAPhys;
- DCLJumpPtr pDCLJump;
- DCLLabelPtr pDCLLabel;
- PeleDCLCompilerDCLDataPtr pLabelPeleDCLCompilerDCLData;
- UInt32 branchTargetPhys;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMAddJumpDCL");
-
- // Recast DCL commands.
- pDCLJump = (DCLJumpPtr) pDCLCommand;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLJump->compilerData;
-
- pDCLLabel = (DCLLabelPtr) pDCLJump->pJumpDCLLabel;
- pLabelPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLLabel->compilerData;
-
- // Allocate new descriptor.
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
-
- if (status == noErr)
- {
- pDMA->operation =
- EndianSwapImm32Bit (kPeleNOP_CMD | // Do nothing
- kPeleBranchAlways | // ... except branch
- kPeleIntNever | // No interrupt
- kPeleWaitNever); // No wait
- pDMA->address = EndianSwapImm32Bit (0);
- pDMA->cmdDep = EndianSwapImm32Bit (0); // Fill in with branch address
- pDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
- }
-
- // Check if label has been resolved.
-
- if (pLabelPeleDCLCompilerDCLData->pDMA != nil)
- {
- FWDebugStr ((ConstStr255Param) "\p ... PeleFWIMAddJumpDCL to resolved label");
-
- // Assume that we never jump to nil
-
- branchTargetPhys = (UInt32) pLabelPeleDCLCompilerDCLData->pDMAPhys;
-
- #ifdef PeleVMDebug
- zzz fix this
- if (((Ptr) (pDCLLabelPCL)) !=
- ((Ptr) (branchTargetPhys)))
- {
- sprintf (debugStr, "Jump target logical %08lx != physical %08lx",
- (long) pDCLLabelPCL,
- (long) branchTargetPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- pDMA->cmdDep = EndianSwap32Bit ((UInt32) branchTargetPhys);
-
- }
- else
- {
- FWDebugStr ((ConstStr255Param) "\p ... PeleFWIMAddJumpDCL to UNRESOLVED label");
-
- // In case the DCL we're branching to already has one unresolved
- // reference, store that one in our branch field so we can put our
- // own address in the DCL. See next comment.
-
- pDMA->cmdDep = (UInt32) (pLabelPeleDCLCompilerDCLData->pDMA);
-
- // Need to resolve label later.
- // This is tricky. Store the (logical) address of the (physical) jump
- // target address in compilerData. Later, we'll update it. Note that
- // if the spot to be updated contains another address (from previous
- // line) then we'll update that one too, and so on.
- pLabelPeleDCLCompilerDCLData->pDMA = (PeleDMAPtr) &(pDMA->cmdDep);
-
- // The resolution of all this is done by PeleFWIMResolveDCLLabel.
- // Labels are resolved as soon as they are added, but we might be
- // branching to a label that hasn't yet been added (it follows us).
- }
-
- // Link previous descriptor.
- if ((status == noErr) && pPeleDMABuildState->pLastBranch)
- {
- *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
- }
-
- // Update build state.
- if (status == noErr)
- {
- // Our new descriptor doesn't need a branch address like others do.
- pPeleDMABuildState->pLastBranch = nil;
- }
-
- // Return results.
- if (status == noErr)
- {
- pPeleDCLCompilerDCLData->pDMA = pDMA;
- pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
- }
- else
- {
- pPeleDCLCompilerDCLData->pDMA = nil;
- pPeleDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddLabelDCL
- //
- // This proc adds a label DCL.
- //zzz not optimal.
- //
-
- static OSStatus PeleFWIMAddLabelDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLLabelPtr pDCLLabel;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- PeleDMAPtr pDMA;
- PhysicalAddress pDMAPhys;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMAddLabelDCL");
-
- // Recast DCL command.
- pDCLLabel = (DCLLabelPtr) pDCLCommand;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLLabel->compilerData;
-
- // Allocate new descriptor.
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
-
- if (status == noErr)
- {
- pDMA->operation =
- EndianSwapImm32Bit (kPeleNOP_CMD | // Do nothing
- kPeleBranchAlways | // ... except branch
- kPeleIntNever | // No interrupt
- kPeleWaitNever); // No wait
- pDMA->address = EndianSwapImm32Bit (0);
- pDMA->cmdDep = EndianSwapImm32Bit (0); // Fill in with branch address
- pDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
- }
-
- // Resolve label.
- // This is complicated. If there were no PCL for a label DCL, we would want
- // to resolve things that point to us (pDCLCommand) to point to the PCL for
- // the next "real" command (a transmit, or whatever). But the next DCL has
- // not yet been compiled, (and it might be another label), so the PCL that we
- // would really like to point to doesn't exist yet.
- //
- // I think that what we do is have a dummy PCL that does correspond to this
- // label. That PCL just does a NOP and falls through to the next PCL (which
- // doesn't exist yet). That's what PeleFWIMPCLLabel created. So we waste a
- // PCL and add a little latency to jumps, because once we jump to this label
- // we have to fall through at least one dummy PCL before we get any work done.
- //
- // A possible future optimization would be to pre-allocate the next non-label
- // PCL, so that we know where it is and we can jump to it, rather than making
- // a dummy PCL as the target. That could be tricky because pre-allocation
- // could constrain us.
- //
- // A possible alternative optimization would be to take the finished PCL
- // program, and scan through it for jumps to NOPs, and bump them forward to
- // the next real command. That could also be tricky if we try to make changes
- // to the program later, though.
-
- if (status == noErr)
- {
- // ResolveDCLLabel will need this. Could we just pass it as an argument instead?
-
- pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
-
- status = PeleFWIMResolveDCLLabel (pDCLLabel);
- }
-
- // Link previous descriptor.
- if ((status == noErr) && pPeleDMABuildState->pLastBranch)
- {
- *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
- }
-
- // Update build state.
- if (status == noErr)
- {
- // Our new descriptor doesn't yet have a branch address. Here's where it goes:
- pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDMA->cmdDep);
- }
-
- // Return results.
- if (status == noErr)
- {
- pPeleDCLCompilerDCLData->pDMA = pDMA;
- pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
- }
- else
- {
- pPeleDCLCompilerDCLData->pDMA = nil;
- pPeleDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddSetTagSyncBitsDCL
- //
- // This proc adds a set tag and sync bits DCL.
- //
-
- static OSStatus PeleFWIMAddSetTagSyncBitsDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- DCLSetTagSyncBitsPtr pDCLSetTagSyncBits;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- PeleDMAPtr pDMA, pDoDMA;
- PhysicalAddress pDMAPhys;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- UInt32 itdmaConfig;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) pDCLCommand;
-
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
-
- // Get Pele FWIM data.
- pPeleFWIMData = pPeleDMABuildState->pPeleFWIMData;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Allocate new descriptors.
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 2);
-
- // Set up descriptors.
- if (status == noErr)
- {
- itdmaConfig = pDCLSetTagSyncBits->tagBits << kPeleITDMAconfigTagPhase;
- itdmaConfig |= pPeleDMABuildState->isochChannelNum << kPeleITDMAconfigChannelPhase;
- // zzz should set correct tx speed (defaults to s100)
- itdmaConfig |= pDCLSetTagSyncBits->syncBits << kPeleITDMAconfigSyncPhase;
- itdmaConfig |= kPeleITDMAconfigRateMode;
-
- // Now here's the hard part: We will overwrite the startOnEvent and stopOnEvent
- // bits. We don't care about stopOnEvent, but there are two possible cases for
- // startOnEvent: 1, the channel has not yet started running, so startOnEvent
- // should be 01 (start on cycle). 2, the channel is already running, so startOnEvent
- // should be 11 (in progress).
- // I believe that changing 01 to 11 may cause the DMA to start immediately.
- // Likewise, changing 11 to 01 might stop the DMA until the next match.
- // What to do...?
- //
- // Hmm, could use 01 the first time, then once the DMA gets going, go change that to
- // 11 so it will work on future passes. That's messy, we have to find each setTagSync
- // prior to the first OUTPUT and then fix them up.
- //
- // Try just setting it to 11. Experiments show that this causes the DMA to run immediately.
- // That doesn't agree with our desired start-on-cylce, but maybe the timestamps gathered
- // by the DV transmit program will allow it to get things cleaned up later. (ugh)
-
- itdmaConfig |= (kPeleEventOccured << kPeleITDMAconfigStartOnEventPhase);
-
- pDoDMA = pDMA;
-
- // Store new tag and sync values in ITDMA config register
- //zzz hardwired to ITA
-
- pDoDMA->operation =
- EndianSwapImm32Bit (kPeleSTORE_QUAD | // Store new settings
- kPeleKEY_SYSTEM |
- kPeleIntNever | // No interrupt
- kPeleWaitNever | // No wait
- 4); // reqCount
- pDoDMA->address = EndianSwap32Bit ((UInt32) &(pPeleRegs->itaControl.configuration));
- pDoDMA->cmdDep = EndianSwapImm32Bit (itdmaConfig); // New config settings
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- pDoDMA++;
-
- // STORE_QUAD has no branch address, so do a NOP and branch.
-
- pDoDMA->operation =
- EndianSwapImm32Bit (kPeleNOP_CMD | // Do nothing
- kPeleIntAlways | // ... except Interrupt
- kPeleBranchAlways | // ... and branch to next descriptor
- kPeleWaitNever); // No wait
- pDoDMA->address = EndianSwapImm32Bit (0);
- pDoDMA->cmdDep = EndianSwapImm32Bit (0); // branch address - will be filled in later.
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- }
-
- // Link previous descriptor.
- if ((status == noErr) && pPeleDMABuildState->pLastBranch)
- {
- *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
- }
-
- // Update build state.
- if (status == noErr)
- {
- // Our new descriptor doesn't yet have a branch address. Here's where it goes:
- pPeleDMABuildState->pLastBranch = (UInt32*) &(pDoDMA->cmdDep);
- }
-
- // Return results.
- if (status == noErr)
- {
- pPeleDCLCompilerDCLData->pDMA = pDMA;
- pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
- }
- else
- {
- pPeleDCLCompilerDCLData->pDMA = nil;
- pPeleDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddUpdateDCLListDCL
- //
- // This proc adds a update DCL list DCL.
- //
-
- static OSStatus PeleFWIMAddUpdateDCLListDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- // These just do the same thing - add an interrupt and sort it out later.
- return PeleFWIMAddCallProcDCL (pPeleDMABuildState, pDCLCommand);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddTimeStampDCL
- //
- // This proc adds a time stamp DCL. This will build PCL commands to read the
- // current cycle counter and write it into the PCL command. The DCL compiler data
- // will point to where the cycle timer is stored in the PCL command.
- //
-
- static OSStatus PeleFWIMAddTimeStampDCL(
- PeleDMABuildStatePtr pPeleDMABuildState,
- DCLCommandPtr pDCLCommand)
- {
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- PeleDMAPtr pDMA, pDoDMA;
- PhysicalAddress pDMAPhys;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
-
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
-
- // Get Pele FWIM data.
- pPeleFWIMData = pPeleDMABuildState->pPeleFWIMData;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Allocate new descriptors.
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 2);
-
- // Set up descriptors.
- if (status == noErr)
- {
- pDoDMA = pDMA;
-
- // Stash a copy of the cycle timer register in the first descriptor
-
- pDoDMA->operation =
- EndianSwapImm32Bit (kPeleLOAD_QUAD | // Store new settings
- kPeleKEY_SYSTEM |
- kPeleIntNever | // No interrupt
- kPeleWaitNever | // No wait
- 4); // reqCount
- pDoDMA->address = EndianSwap32Bit ((UInt32) &(pPeleRegs->isochronousCycleTimer));
- pDoDMA->cmdDep = EndianSwapImm32Bit (0); // Will load it here
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- pDoDMA++;
-
- // LOAD_QUAD has no branch address, so do a NOP and branch.
-
- pDoDMA->operation =
- EndianSwapImm32Bit (kPeleNOP_CMD | // Do nothing
- kPeleIntAlways | // ... except Interrupt
- kPeleBranchAlways | // ... and branch to next descriptor
- kPeleWaitNever); // No wait
- pDoDMA->address = EndianSwapImm32Bit (0);
- pDoDMA->cmdDep = EndianSwapImm32Bit (0); // branch address - will be filled in later.
- pDoDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
-
- }
-
- // Link previous descriptor.
- if ((status == noErr) && pPeleDMABuildState->pLastBranch)
- {
- *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
- }
-
- // Update build state.
- if (status == noErr)
- {
- // Our new descriptor doesn't yet have a branch address. Here's where it goes:
- pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDoDMA->cmdDep);
- }
-
- // Return results.
- if (status == noErr)
- {
- pPeleDCLCompilerDCLData->pDMA = pDMA;
- pPeleDCLCompilerDCLData->pDMAPhys = pDMAPhys;
- }
- else
- {
- pPeleDCLCompilerDCLData->pDMA = nil;
- pPeleDCLCompilerDCLData->pDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAddStopDCL
- //
- // This proc adds a (virtual) Stop DCL.
- //
-
- static OSStatus PeleFWIMAddStopDCL(
- PeleDMABuildStatePtr pPeleDMABuildState)
- {
- PeleDMAPtr pDMA;
- PhysicalAddress pDMAPhys;
- PeleFWIMDataPtr pPeleFWIMData;
- OSStatus status = noErr;
-
- // Get Pele FWIM data.
- pPeleFWIMData = pPeleDMABuildState->pPeleFWIMData;
-
- // Allocate new descriptor.
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
-
- // Set up descriptor.
- if (status == noErr)
- {
- pDMA->operation = EndianSwapImm32Bit (kPeleSTOP_CMD);
- pDMA->address = EndianSwapImm32Bit (0);
- pDMA->cmdDep = EndianSwapImm32Bit (0);
- pDMA->result = EndianSwapImm32Bit (0);
- }
-
- // Link previous descriptor.
- if ((status == noErr) && pPeleDMABuildState->pLastBranch)
- {
- *(pPeleDMABuildState->pLastBranch) = EndianSwap32Bit ((UInt32) pDMAPhys);
- }
-
- // Update build state.
- if (status == noErr)
- {
- pPeleDMABuildState->pLastBranch = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDMAStart
- //
- // This proc creates a build state record and a NOP descriptor to start the
- // program.
- //
-
- static OSStatus PeleFWIMDMAStart(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleDMABuildStatePtr *ppPeleDMABuildState,
- PeleDMAPtr *ppStartDMA)
- {
- PeleDMABuildStatePtr pPeleDMABuildState;
- PeleDMAPtr pDMA;
- PhysicalAddress pDMAPhys;
- OSStatus status = noErr;
-
- // Probably don't need any of this
-
- // Allocate build state record.
- status = PeleFWIMAllocateDMABuildState (pPeleFWIMData, &pPeleDMABuildState);
-
- // Allocate new descriptor.
- if (status == noErr)
- status = PeleFWIMAllocateDMA (pPeleDMABuildState, &pDMA, &pDMAPhys, 1);
-
- // Set up descriptor.
- if (status == noErr)
- {
- pDMA->operation =
- EndianSwapImm32Bit (kPeleNOP_CMD | // do nothing
- kPeleBranchAlways | // ... except branch
- kPeleIntNever | // No interrupt
- kPeleWaitNever); // No wait
- pDMA->address = EndianSwapImm32Bit (0);
- pDMA->cmdDep = EndianSwapImm32Bit (0);
- pDMA->result = EndianSwapImm32Bit (0); // modified when DMA complete
- }
-
- // Fill in build state record.
- if (status == noErr)
- {
- pPeleDMABuildState->pPeleFWIMData = pPeleFWIMData;
-
- // Our new descriptor doesn't yet have a branch address. Here's where it goes:
- pPeleDMABuildState->pLastBranch = (UInt32 *) &(pDMA->cmdDep);
- }
-
- // Return results.
- if (status == noErr)
- {
- *ppPeleDMABuildState = pPeleDMABuildState;
- *ppStartDMA = (PeleDMAPtr) pDMAPhys; // zzz rename field
- }
- else
- {
- *ppPeleDMABuildState = nil;
- *ppStartDMA = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMResolveDCLLabel
- //
- // This proc resolves the given DCL label.
- //
-
- static OSStatus PeleFWIMResolveDCLLabel(
- DCLLabelPtr pDCLLabel)
- {
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- PeleDMAPtr *pLabelDependency,
- *pNextLabelDependency;
- UInt32 branchTargetPhys;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMResolveDCLLabel");
-
- // The label pDCLLabel has just been added to the PCL program. It may already
- // be the branch target of one or more existing PCLs. If so, they have stashed
- // a pointer to where they hold their branch target in pDCLLabel->compilerData.
- // Furthermore, if what is pointed to is not nil, it is another pointer to an
- // unresolved label, etc. So we follow that chain, filling in our real PCL
- // address. Note that we will need to fill in the physical address, since now
- // is the final stage in assigning jump addresses.
-
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLLabel->compilerData;
-
- // Resolve all of the dependencies.
- if (pPeleDCLCompilerDCLData->pDMA != nil)
- {
- //zzz what if label DCL is last in list???
-
- // Resolve label to this descriptor.
- {
- pLabelDependency = (PeleDMAPtr *) pPeleDCLCompilerDCLData->pDMA;
- while (pLabelDependency != nil)
- {
- FWDebugStr ((ConstStr255Param) "\p ... PeleFWIMResolveDCLLabel resolved dependency");
-
- // Assume no branch to nil
-
- branchTargetPhys = (UInt32) pPeleDCLCompilerDCLData->pDMAPhys;
-
- pNextLabelDependency = (PeleDMAPtr *) *pLabelDependency;
- *pLabelDependency = (PeleDMAPtr) EndianSwap32Bit (branchTargetPhys);
- pLabelDependency = pNextLabelDependency;
- #ifdef PeleVMDebug
- zzz fix this
- if (((Ptr) (pPCL)) !=
- ((Ptr) (branchTargetPhys)))
- {
- sprintf (debugStr, "Resolved target logical %08lx != physical %08lx",
- (long) pPCL,
- (long) branchTargetPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- }
- }
-
- // resolve is called after we create the label but before we fill in
- // its compiler data. this is not really required any more:
-
- pPeleDCLCompilerDCLData->pDMA = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDCLCompilerNotification
- //
- // This proc handles update notifications for the DCL to PCL compiler.
- //
-
- static OSStatus PeleFWIMDCLCompilerNotification(
- DCLProgramID dclProgramID,
- UInt32 notificationType,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- OSStatus status = noErr;
-
- switch (notificationType)
- {
- case kFWDCLUpdateNotification :
- status = PeleFWIMDCLCompilerUpdateNotification (dclProgramID,
- dclCommandList,
- numDCLCommands);
- break;
-
- case kFWDCLModifyNotification :
- status = PeleFWIMDCLCompilerModifyNotification (dclProgramID,
- dclCommandList,
- numDCLCommands);
- break;
-
- default :
- status = paramErr;
- break;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDCLCompilerUpdateNotification
- //
- // This proc handles update notifications for the DCL to PCL compiler. This will
- // do any neccessary CheckPointIOs and update any DCL status fields.
- //zzz do the right stuff in here
- //
-
- static OSStatus PeleFWIMDCLCompilerUpdateNotification(
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- DCLCommandPtr pDCLCommand;
- UInt32 dclCommandNum;
- OSStatus status = noErr;
-
- for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
- {
- pDCLCommand = dclCommandList[dclCommandNum];
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLTimeStampOp :
- PeleFWIMUpdateDCLTimeStamp (pDCLCommand);
- break;
-
- case kDCLReceivePacketStartOp :
- PeleFWIMUpdateDCLReceivePacketStart (pDCLCommand);
- break;
-
- // I think we might want to CheckpointIO () on the live buffers, etc...?
- default :
- break;
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMUpdateDCLTimeStamp
- //
- // This proc updates a DCL time stamp. It reads the time stamp out of a
- // descriptor and writes it into the timeStamp field of the DCL.
- //
-
- static OSStatus PeleFWIMUpdateDCLTimeStamp(
- DCLCommandPtr pDCLCommand)
- {
- DCLTimeStampPtr pDCLTimeStamp;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- UInt32 timeStamp;
- OSStatus status = noErr;
-
- // Recast DCL command.
- pDCLTimeStamp = (DCLTimeStampPtr) pDCLCommand;
-
- // Copy time stamp from LOAD_QUAD descriptor.
- // Add one cycle since we're running ahead.
- //zzz Actually Pele runs 0 to 1 ahead depending on packet sizes.
- //zzz can't just add 1, that could result in an illegal cycle #8000
- //zzz fix add-1 in LynxFWIM too
-
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTimeStamp->compilerData;
- timeStamp = EndianSwap32Bit (pPeleDCLCompilerDCLData->pDMA->cmdDep);
- if ((timeStamp >> 12) & 0x1fff == 7999)
- pDCLTimeStamp->timeStamp = (timeStamp & 0xfe000fff) + (1 << 25);
- else pDCLTimeStamp->timeStamp = timeStamp + (1 << 12);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMUpdateDCLReceivePacketStart
- //
- // This proc updates a receive packet start DCL time stamp.
- // It fakes the packet header (and should maybe also call checkpointIO).
- //
-
- static OSStatus PeleFWIMUpdateDCLReceivePacketStart(
- DCLCommandPtr pDCLCommand)
- {
- DCLTransferPacketPtr pDCLTransferPacket;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- PeleDMAPtr pDMA;
- UInt32 receivedCount, result, fakeHeader;
-
- // Recast DCL command.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
-
- pDMA = pPeleDCLCompilerDCLData->pDMA;
- result = EndianSwap32Bit (pDMA->result);
-
- // Pele stripped the header, so fake one.
-
- receivedCount = (pDCLTransferPacket->size - 4); // reqCount we gave Pele
- receivedCount -= (result & kPeleResCountMask); // subtract resCount to get receive count
-
- // Construct fake packet header. Sync and tag are 0.
- // zzz should fill in channel number
-
- fakeHeader = receivedCount << kFWIsochDataLengthPhase;
- fakeHeader |= kFWTCodeIsochronousBlock << kPelePacketTCodePhase;
-
- *((UInt32 *) pDCLTransferPacket->buffer) = fakeHeader;
-
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDCLCompilerModifyNotification
- //
- // This proc handles modification notifications for the DCL to PCL compiler.
- //zzz break this routine up
- //
-
- static OSStatus PeleFWIMDCLCompilerModifyNotification(
- DCLProgramID dclProgramID,
- DCLCommandPtr *dclCommandList,
- UInt32 numDCLCommands)
- {
- DCLCommandPtr pDCLCommand;
- DCLJumpPtr pDCLJump;
- DCLLabelPtr pDCLLabel;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData,
- pLabelPeleDCLCompilerDCLData;
- PeleDMAPtr pJumpDMA,
- pLabelDMA;
-
- UInt32 dclCommandNum;
- UInt32 branchTargetPhys;
-
- OSStatus status = noErr;
-
- for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
- {
- // Get DCL command to update.
- pDCLCommand = *dclCommandList++;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
-
- // Update command.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLJumpOp :
-
- // Recast.
- pDCLJump = (DCLJumpPtr) pDCLCommand;
-
- // Get label we're jumping to.
- pDCLLabel = pDCLJump->pJumpDCLLabel;
- pLabelPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLLabel->compilerData;
-
- // Get descriptors for jump and label DCLs.
- pJumpDMA = pPeleDCLCompilerDCLData->pDMA;
- pLabelDMA = pLabelPeleDCLCompilerDCLData->pDMA;
-
- branchTargetPhys = (UInt32) pLabelPeleDCLCompilerDCLData->pDMAPhys;
-
- // Update jump descriptor.
- pJumpDMA->cmdDep = EndianSwap32Bit ((UInt32) branchTargetPhys);
-
- #ifdef PeleVMDebug
- if (((Ptr) (pLabelPCL)) !=
- ((Ptr) (branchTargetPhys)))
- {
- sprintf (debugStr, "Updated jump logical %08lx != physical %08lx",
- (long) pLabelPCL,
- (long) branchTargetPhys);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- break;
-
- case kDCLSendPacketWithHeaderStartOp :
- //zzz support other transfer packet commands.
-
- FWDebugStr ((ConstStr255Param) "/pOops, tried to update buffer, don't know how!");
-
- // What would we do?
- // We can't do what's done below - that fills in new PCL buffer addresses. They aren't yet known.
- // What we want is a PrepareMemoryForIO that covers all buffers in the new scheme. I notice that
- // we don't actually modify the base DCLs - I think we will have to do that. So make one pass to
- // modify the base DCLs. Then call the general-purpose memory preparation routine, and let it
- // create an all-new ioPrep (keep the old one). Once that's done, we can re-scan the list of
- // changes and make updates knowing the new physical addresses. Finally, once the updates are
- // all in place, it's impossible for any stale DMA to take place, so we can CheckpointIO on
- // the old ioPrep struct and free its resources. [Technically we should wait one packet to make
- // sure that whatever Pele's current DMA engine is doing is up to date. Probably a good-enough
- // way to do this is to postpone the CheckpointIO until before the NEXT round of updates, though
- // that is somewhat wasteful if it ties down old buffers that aren't in use anymore...]
- //
- // We should find a safe way to make multiple updates to a PCL. The user is in trouble anyway
- // if we're changing a PCL while it runs, because they'll get the wrong data, but we want to
- // make sure we don't send an illegally large packet (bad for 1394 bus) or overflow our receiver
- // (could be bad for Pele). Perhaps we should copy command[0], set it to NOP+last, update the
- // others, then update command[0]. That's safe unless we are inside the PCL but past command[0].
- // After we set command[0] to NOP, we can check the DMA current cmd and make sure it is elsewhere.
- //
- // I don't suppose the user is required to use jump-updates to deactivate part of the program
- // before updating that part? That would be 100% safe if we know the jump-update worked on time.
- //
- // For safety we should probably pre-allocate a physAddr table and a rangeTable for two ioPrep
- // structs, then we don't have to do any allocs here. (though PrepareMemForIO might anyway).
- // We know that the total number of buffers can't change, so rangeTable is OK. When we prepare
- // the physAddr table we should work out both the true size and the worst-case size. Use the
- // worst-case for alloc, use the true for PrepareMemoryForIO
-
- #if 0
- // Recast.
- pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
-
- // Get PCL.
- pTransferPacketPCL =
- PeleFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLTransferPacket);
-
- // Update buffer size of transfer PCL.
- pclControl = EndianSwap32Bit (pTransferPacketPCL->buffer[0].control);
- pclControl = (pclControl & ~kPeleDMA_TransferCount) |
- ((pDCLTransferPacket->size) << kPeleDMA_TransferCountPhase);
- pTransferPacketPCL->buffer[0].control = EndianSwap32Bit (pclControl);
-
- // Update buffer address of transfer PCL.
- // WARNING WARNING this won't work with VM on - this is a logical address
- pTransferPacketPCL->buffer[0].address =
- (UInt32 *) EndianSwap32Bit ((UInt32) pDCLTransferPacket->buffer);
- #endif
- break;
-
- default :
-
- break;
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAllocateDMABuildState
- //
- // This proc allocates a DMA build state record.
- //zzz we really don't need this. should be allocated by other methods (stack?)
- //
-
- static OSStatus PeleFWIMAllocateDMABuildState(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleDMABuildStatePtr *ppPeleDMABuildState)
- {
- PeleDMABuildStatePtr pPeleDMABuildState;
- OSStatus status = noErr;
-
- // Allocate memory for record.
- pPeleDMABuildState =
- (PeleDMABuildStatePtr) PoolAllocateResident (sizeof (PeleDMABuildState), true);
- if (pPeleDMABuildState == nil)
- status = memFullErr;
-
- // Return results.
- if (status == noErr)
- *ppPeleDMABuildState = pPeleDMABuildState;
- else
- *ppPeleDMABuildState = nil;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAllocateDMA
- //
- // This proc allocates a block of consecutive DBDMA descriptors.
- //
-
- static OSStatus PeleFWIMAllocateDMA(
- PeleDMABuildStatePtr pPeleDMABuildState,
- PeleDMAPtr *ppDMA,
- PhysicalAddress *ppDMAPhys,
- UInt32 count)
- {
- PeleDMAPoolDataPtr pPeleDMAPoolData;
- PeleDMAPtr pDMA,
- dmaPool;
- UInt32 dmaPoolPhys;
- UInt32 nextFreeDMA;
- IOPreparationTable *ioPrep;
- UInt32 pageSize, allocSize;
- Ptr p;
- OSStatus status = noErr;
-
- // Get pool data record.
- pPeleDMAPoolData = pPeleDMABuildState->pPeleDMAPoolDataList;
-
- // Get PCL pool and next free PCL index.
- if (pPeleDMAPoolData != nil)
- {
- dmaPool = pPeleDMAPoolData->alignedDMAPoolBase;
- dmaPoolPhys = pPeleDMAPoolData->alignedDMAPoolBasePhys;
- nextFreeDMA = pPeleDMAPoolData->nextFreeDMA;
- }
- else
- {
- dmaPool = nil;
- }
-
- // Allocate new pool if current pool is exhausted.
- // This pool needs to be aligned to the DBDMA size for the compilation logic
- // to work properly. Pool size can exceed one phys page as long as we have an
- // allocator which gives us contiguous pages.
-
- // zzz change this to store a freeCount, not a nextFree, so we can compute freeCount
- // based on the page size & alignment we happen to find.
-
- if ((dmaPool == nil) || (nextFreeDMA + count > kDMAPoolSize))
- {
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMAllocateDMA - allocating a pool of DBDMA");
-
- pageSize = GetLogicalPageSize ();
- allocSize = sizeof (PeleDMAPoolData) + sizeof (PeleDMA);
-
- // Not knowing if MemAllocPhysCont returns page-aligned data, we need to
- // add one page to align and one more to flush out the end of the struct.
- // (Could be done more tightly.)
-
- allocSize = (allocSize / pageSize) + 3; // sloppy
-
- p = MemAllocatePhysicallyContiguous (allocSize * pageSize, true);
- if (p != nil)
- {
- // Page align
- pPeleDMAPoolData = (PeleDMAPoolDataPtr)
- (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1));
-
- // Store original
- pPeleDMAPoolData->poolAllocatedAddress = (LogicalAddress) p;
-
- ioPrep = &pPeleDMAPoolData->ioPrep;
-
- // Prepare for IO and get physical address
- ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
- ioPrep->addressSpace = kCurrentAddressSpaceID; // default
- ioPrep->granularity = 0; // do it all now
- ioPrep->firstPrepared = 0;
- ioPrep->mappingEntryCount = allocSize - 1; // # of pages we will use
- ioPrep->logicalMapping = 0;
- ioPrep->physicalMapping = pPeleDMAPoolData->physAddrs; // return list of phys addrs
- ioPrep->rangeInfo.range.base = (void *) pPeleDMAPoolData;
- ioPrep->rangeInfo.range.length = (allocSize - 1) * pageSize;
-
- // The CheckpointIO is in PeleFWIMDeallocateDMAPools
- status = PrepareMemoryForIO (ioPrep);
- if (status != noErr)
- {
- sprintf (debugStr, "PCL Pool PrepMemIO status %ld logical %08lx physical %08lx len %lx",
- (long) status,
- (long) ioPrep->rangeInfo.range.base,
- (long) pPeleDMAPoolData->physAddrs[0],
- (long) ioPrep->rangeInfo.range.length);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
-
- pPeleDMAPoolData->pNextPeleDMAPoolData =
- pPeleDMABuildState->pPeleDMAPoolDataList;
- pPeleDMABuildState->pPeleDMAPoolDataList = pPeleDMAPoolData;
- // Never use dmaPoolDummy. (This is the only place) It does not index
- // the true aligned PCLs. Use alignedDMAPoolBase as an array instead.
- pPeleDMAPoolData->alignedDMAPoolBase = (PeleDMAPtr)
- (((UInt32) &(pPeleDMAPoolData->dmaPoolDummy[1])) & kDMAAlignmentMask);
-
- pPeleDMAPoolData->alignedDMAPoolBasePhys =
- (UInt32) pPeleDMAPoolData->physAddrs[0] +
- ((UInt32) pPeleDMAPoolData->alignedDMAPoolBase - (UInt32) pPeleDMAPoolData);
-
- nextFreeDMA = 0;
- dmaPool = pPeleDMAPoolData->alignedDMAPoolBase;
- dmaPoolPhys = pPeleDMAPoolData->alignedDMAPoolBasePhys;
- }
- else
- {
- status = memFullErr;
- }
- }
-
- // Allocate PCL from pool.
- if (status == noErr)
- {
- pDMA = &(dmaPool[nextFreeDMA]);
- nextFreeDMA += count;
- pPeleDMAPoolData->nextFreeDMA = nextFreeDMA;
-
- #ifdef PeleVMDebug
- if (((Ptr) (pDMA)) != ((Ptr) (dmaPoolPhys + (((UInt32) pDMA) - ((UInt32) dmaPool)))))
- {
- sprintf (debugStr, "DBDMA alloc logical %08lx != physical %08lx",
- (long) pDMA,
- (long) (dmaPoolPhys + (((UInt32) pDMA) - ((UInt32) dmaPool))));
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- #endif
- }
-
- // Return results.
- if (status == noErr)
- {
- *ppDMA = pDMA;
- *ppDMAPhys = (PhysicalAddress) (dmaPoolPhys + (((UInt32) pDMA) - ((UInt32) dmaPool)));
- }
- else
- {
- *ppDMA = nil;
- *ppDMAPhys = nil;
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDeallocateDMAPools
- //
- // This proc deallocates the given list of descriptor pools.
- //
-
- static void PeleFWIMDeallocateDMAPools(
- PeleDMAPoolDataPtr pPeleDMAPoolDataList)
- {
- PeleDMAPoolDataPtr pPeleDMAPoolData,
- pNextPeleDMAPoolData;
- OSStatus status = noErr;
-
- // Deallocate each pool in list.
- pPeleDMAPoolData = pPeleDMAPoolDataList;
- while (pPeleDMAPoolData != nil)
- {
- pNextPeleDMAPoolData = pPeleDMAPoolData->pNextPeleDMAPoolData;
- status = CheckpointIO (pPeleDMAPoolData->ioPrep.preparationID, kNilOptions);
- if (status != noErr)
- {
- sprintf (debugStr, "PCL Pool CheckpointIO status %ld ID was %08lx",
- (long) status,
- (long) pNextPeleDMAPoolData->ioPrep.preparationID);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- if (MemDeallocatePhysicallyContiguous (pPeleDMAPoolData->poolAllocatedAddress) != noErr)
- FWDebugStr ((ConstStr255Param) "\p Dealloc error!!");
- pPeleDMAPoolData = pNextPeleDMAPoolData;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAllocateIsochPort
- //
- // This routine will allocate an isochronous channel.
- //zzz must make sure that port is not already in use.
- //zzz should do more error checking.
- //zzz we may need to keep a list of isoch port data records.
- //
-
- static OSStatus PeleFWIMAllocateIsochPort(
- FWIMAllocateIsochPortParamsPtr
- pFWIMAllocateIsochPortParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleIsochPortDataPtr pPeleIsochPortData = nil;
- PeleRegistersPtr pPeleRegs;
- PeleDBDMAChannelRegistersPtr
- pDBDMAChannel, pDBDMAChannel2;
- PeleIsochControlRegistersPtr
- pIsochControl, pIsochControl2;
- UInt32 isochChannelNum;
- UInt32 dmaChannelNum;
- Boolean talking;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMAllocateIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAllocateIsochPortParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAllocateIsochPortParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Get base address of Pele registers.
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Are we talking?
- talking = pFWIMAllocateIsochPortParams->talking;
-
- if (talking)
- {
- pDBDMAChannel = &(pPeleRegs->isochTransmitA);
- pIsochControl = &(pPeleRegs->itaControl);
- dmaChannelNum = kIsochTransmitDMA;
-
- pDBDMAChannel2 = nil;
- pIsochControl2 = nil;
- }
- else
- {
- pDBDMAChannel = &(pPeleRegs->isochReceiveA);
- pIsochControl = &(pPeleRegs->iraControl);
- dmaChannelNum = kIsochReceiveDMA;
-
- // Pele can only receive one tag (unlike Lynx which receives all tags)
- // Only tags 0 and 1 are used today, so we'll run both IRDMA contextx,
- // one for each tag. Both of them will run, but one will stall at the
- // first INPUT_LAST because no data will arrive. This will cause a
- // problem only if there is a callProc, update, or timeStamp prior to
- // the first INPUT_LAST, because both DMAs will try to execute it.
-
- // Maybe (the plot thickens...) we could advance the "B" DMA starting
- // point to the first INPUT_LAST before activating the DMAs. If we
- // start "A" first then "B", things still happen in order.
-
- pDBDMAChannel2 = &(pPeleRegs->isochReceiveB);
- pIsochControl2 = &(pPeleRegs->irbControl);
- }
-
- // Create an isoch port data record.
- pPeleIsochPortData =
- (PeleIsochPortDataPtr) PoolAllocateResident (sizeof (PeleIsochPortData), true);
- if (pPeleIsochPortData != nil)
- {
- pPeleFWIMData->lynxIsochPortDataList[dmaChannelNum] = pPeleIsochPortData;
- pPeleIsochPortData->originalDCLProgramID =
- pFWIMAllocateIsochPortParams->dclProgramID;
- pPeleIsochPortData->translatedDCLProgramID = kInvalidDCLProgramID;
- pPeleIsochPortData->channelNum = pFWIMAllocateIsochPortParams->channelNum;
- pPeleIsochPortData->speed = pFWIMAllocateIsochPortParams->speed;
- pPeleIsochPortData->talking = talking;
- }
- else
- {
- status = memFullErr;
- }
-
- // Compile a DBDMA program from DCL program.
- if (status == noErr)
- {
- // Check if DBDMA program must be translated.
- if (PeleFWIMIsCompilableDCLProgram (pPeleIsochPortData->originalDCLProgramID))
- {
- pPeleIsochPortData->dclProgramID = pPeleIsochPortData->originalDCLProgramID;
- }
- else
- {
- //zzz need to be able to deallocate this.
- status = FWTranslateDCLProgram (pPeleIsochPortData->originalDCLProgramID,
- &(pPeleIsochPortData->translatedDCLProgramID));
- if (status == noErr)
- {
- pPeleIsochPortData->dclProgramID =
- pPeleIsochPortData->translatedDCLProgramID;
- }
- }
-
- // Compile the DCL program.
- if (status == noErr)
- {
- status = PeleFWIMCompileDCLProgram
- (pPeleFWIMData,
- pPeleIsochPortData->dclProgramID,
- dmaChannelNum,
- pPeleIsochPortData->channelNum,
- pPeleIsochPortData->speed);
- }
-
- // Set start, stop, and release procedures for DCL program.
- if (status == noErr)
- {
- if (talking)
- {
- FWSetDCLProgramStartProc (pPeleIsochPortData->dclProgramID,
- PeleFWIMStartTalkingDCLProgram);
- FWSetDCLProgramStopProc (pPeleIsochPortData->dclProgramID,
- PeleFWIMStopTalkingDCLProgram);
- FWSetDCLProgramReleaseProc (pPeleIsochPortData->dclProgramID,
- PeleFWIMReleaseDCLProgram);
- }
- else
- {
- FWSetDCLProgramStartProc (pPeleIsochPortData->dclProgramID,
- PeleFWIMStartListeningDCLProgram);
- FWSetDCLProgramStopProc (pPeleIsochPortData->dclProgramID,
- PeleFWIMStopListeningDCLProgram);
- FWSetDCLProgramReleaseProc (pPeleIsochPortData->dclProgramID,
- PeleFWIMReleaseDCLProgram);
- }
- }
- }
-
- // Set up appropriate DMA channel.
- if (status == noErr)
- {
- // Quiet the DMA channel.
- pDBDMAChannel->channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO ();
-
- if (pDBDMAChannel2)
- {
- pDBDMAChannel2->channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO ();
- }
-
- isochChannelNum = pPeleIsochPortData->channelNum;
-
- // Set channel to transmit on if we're talking.
- if (talking)
- {
- // zzz This will transmit at s100 rate. Lynx sample code does the same.
- pIsochControl->configuration =
- EndianSwap32Bit ((isochChannelNum << kPeleITDMAconfigChannelPhase) |
- kPeleITDMAconfigRateMode);
- SynchronizeIO ();
- }
-
- // Set up comparators to receive on this port's channel.
- if (!talking)
- {
- // BufferMode means one packet per INPUT_LAST, according to the spec.
-
- // This clears the startOnEvent. Later, we may set it to 11 to force
- // a start, depending on a compile option. Either way, we should instead
- // set it to 01 (start on cycle) if we are so requested, but we don't. zzz
-
- // Receive tag 0 on IRA
- pIsochControl->configuration =
- EndianSwap32Bit (kPeleIRDMAconfigBufferMode |
- (0 << kPeleIRDMAconfigTagPhase) |
- (isochChannelNum << kPeleIRDMAconfigChannelPhase));
- SynchronizeIO ();
-
- if (pIsochControl2)
- {
- // Receive tag 1 on IRB
- pIsochControl2->configuration =
- EndianSwap32Bit (kPeleIRDMAconfigBufferMode |
- (1 << kPeleIRDMAconfigTagPhase) |
- (isochChannelNum << kPeleIRDMAconfigChannelPhase));
- SynchronizeIO ();
- }
- }
-
- // Set our data for port.
- pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData =
- (UInt32) pPeleIsochPortData;
- }
-
- // Clean up on error.
- if (status != noErr)
- {
- if (pPeleIsochPortData != nil)
- _PeleFWIMReleaseIsochPort (pPeleFWIMData, pPeleIsochPortData);
- }
-
- // Complete FWIM command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMReleaseIsochPort
- //
- // This routine will release resources allocated for the given isochronous
- // channel.
- //
-
- static OSStatus PeleFWIMReleaseIsochPort(
- FWIMReleaseIsochPortParamsPtr
- pFWIMReleaseIsochPortParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleIsochPortDataPtr pPeleIsochPortData;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMReleaseIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMReleaseIsochPortParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMReleaseIsochPortParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Get isoch port data.
- pPeleIsochPortData = (PeleIsochPortDataPtr)
- pFWIMReleaseIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Release resources for isoch port.
- if (pPeleIsochPortData != nil)
- status = _PeleFWIMReleaseIsochPort (pPeleFWIMData, pPeleIsochPortData);
-
- // Complete FWIM command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // _PeleFWIMReleaseIsochPort
- //
- // This routine will release resources allocated for the given isochronous
- // channel.
- //
-
- static OSStatus _PeleFWIMReleaseIsochPort(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleIsochPortDataPtr pPeleIsochPortData)
- {
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData = nil;
- OSStatus status = noErr;
-
- // Release DCL resources.
- if (pPeleIsochPortData->originalDCLProgramID != kInvalidDCLProgramID)
- status = FWReleaseDCLProgram (pPeleIsochPortData->originalDCLProgramID);
-
- // Deallocate isoch port data record.
- PoolDeallocate ((Ptr) pPeleIsochPortData);
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMStartIsochPort
- //
- // Start up the given isochronous port on the given sync event using the
- // given buffer.
- //
-
- static OSStatus PeleFWIMStartIsochPort(
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleIsochPortDataPtr pPeleIsochPortData;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMStartIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Get isoch port data.
- pPeleIsochPortData = (PeleIsochPortDataPtr)
- pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Start DCL program.
- if (status == noErr)
- status = FWStartDCLProgram (pPeleIsochPortData->originalDCLProgramID);
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMStopIsochPort
- //
- // Stop the given isochronous port on the given sync event.
- //
-
- static OSStatus PeleFWIMStopIsochPort(
- FWIMIsochPortControlParamsPtr
- pFWIMIsochPortControlParams,
- UInt32 *pCommandAcceptance)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleIsochPortDataPtr pPeleIsochPortData;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMStopIsochPort");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
-
- // Set pending command.
- pPeleFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
- pPeleFWIMData->pendingFWIMCommandStatus = kPelePendingFWIMCommandBusy;
-
- // Get isoch port data.
- pPeleIsochPortData = (PeleIsochPortDataPtr)
- pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
-
- // Stop DCL program.
- if (status == noErr)
- status = FWStopDCLProgram (pPeleIsochPortData->originalDCLProgramID);
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
-
- // Return command acceptance.
- //zzz what if we call FWIMCommandIsComplete before returning this???
- //zzz well, it still works, but will it always?
- //zzz actually, when we switch to the dispatch table, each routine can return
- //zzz the appropriate acceptance, so don't worry about it for now.
- *pCommandAcceptance = kFWIMCommandAcceptNoMore;
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMStartTalkingDCLProgram
- //
- // This routine starts running the given DCL program.
- //
-
- static OSStatus PeleFWIMStartTalkingDCLProgram(
- DCLProgramID dclProgramID)
- {
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- UInt32 eventCycle;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMStartTalkingDCLProgram");
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
- if (status == noErr)
- pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
-
- // Get base address of Pele registers.
- if (status == noErr)
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Start the DMA engine.
- if (status == noErr)
- {
- // We'll report statistics at the end of the transmit, if FireBug enabled.
- // pPeleRegs->fifoOverUnderErrorCounters = EndianSwapImm32Bit (0);
-
- // Load a physical address (already known)
- pPeleRegs->isochTransmitA.commandPtr =
- EndianSwap32Bit ((UInt32) pPeleDCLCompilerEngineData->pStartDMA);
- SynchronizeIO ();
-
- // zzz We should satisfy the start condition of the DCL program.
- // But for now, the only known DCL program is DV transmit, and it will work
- // as long as we start on a cycle number whose low 4 bits are zero.
-
- pPeleRegs->itaControl.configuration |=
- EndianSwapImm32Bit (kPeleEventCycleNumber << kPeleITDMAconfigStartOnEventPhase);
- SynchronizeIO ();
-
- eventCycle = EndianSwap32Bit (pPeleRegs->isochronousCycleTimer);
-
- // Add 50 cycles. If that would give us a cycle number > 7999, wrap around
-
- if (((eventCycle & kPeleICTCount) >> kPeleICTCountPhase) > 7949)
- eventCycle += (193 << kPeleICTCountPhase);
-
- eventCycle += (50 << kPeleICTCountPhase);
-
- // Make sure low 4 bits are zero
-
- eventCycle = (eventCycle >> (kPeleICTCountPhase + 4)) << (kPeleICTCountPhase + 4);
-
- pPeleRegs->itaControl.eventCycle = EndianSwap32Bit (eventCycle);
- SynchronizeIO ();
-
- // Start DMA.
- pPeleRegs->isochTransmitA.channelControl = EndianSwapImm32Bit (kPeleSetRun);
- SynchronizeIO ();
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMStartListeningDCLProgram
- //
- // This routine starts running the given DCL program.
- //
-
- static OSStatus PeleFWIMStartListeningDCLProgram(
- DCLProgramID dclProgramID)
- {
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMStartListeningDCLProgram");
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
- if (status == noErr)
- pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
-
- // Get base address of Pele registers.
- if (status == noErr)
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Start the DMA engine.
- if (status == noErr)
- {
- // Load a physical address for tag 0 program
- pPeleRegs->isochReceiveA.commandPtr =
- EndianSwap32Bit ((UInt32) pPeleDCLCompilerEngineData->pStartDMA);
- SynchronizeIO ();
-
- //zzz might be a good idea to advance the tag 1 program to the first INPUT_LAST
- // so we don't double up any callprocs, timestamps, updates, etc.
-
- // Load a physical address for tag 1 program
- pPeleRegs->isochReceiveB.commandPtr =
- EndianSwap32Bit ((UInt32) pPeleDCLCompilerEngineData->pStartDMA);
- SynchronizeIO ();
-
- //zzz Note, we are supposed to honor start-on-cycle requests (see the compiler).
- // But the sample code all works if we just start immediately.
-
- #ifdef PELE_NO_START_ON_RUN
- // Some Pele parts can't just start on event 00, they require a cycle-match.
- // Actually, the DMA will run, but no data enters the FIFO, so nothing happens.
- // But setting the event to 11 will make Pele think it already started:
-
- pPeleRegs->iraControl.configuration |=
- EndianSwapImm32Bit (kPeleEventOccured << kPeleIRDMAconfigStartOnEventPhase);
- SynchronizeIO ();
-
- pPeleRegs->irbControl.configuration |=
- EndianSwapImm32Bit (kPeleEventOccured << kPeleIRDMAconfigStartOnEventPhase);
- SynchronizeIO ();
- #endif
-
- // Start DMA.
- pPeleRegs->isochReceiveA.channelControl = EndianSwapImm32Bit (kPeleSetRun);
- SynchronizeIO ();
-
- // Start DMA.
- pPeleRegs->isochReceiveB.channelControl = EndianSwapImm32Bit (kPeleSetRun);
- SynchronizeIO ();
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMStopTalkingDCLProgram
- //
- // This routine stops running the given DCL program.
- //
-
- static OSStatus PeleFWIMStopTalkingDCLProgram(
- DCLProgramID dclProgramID)
- {
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMStopTalkingDCLProgram");
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
- if (status == noErr)
- pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
-
- // Get base address of Pele registers.
- if (status == noErr)
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Stop the DMA engine.
- if (status == noErr)
- {
- // Stop the DMA.
- // zzzCould be more graceful, not send partial packet?
- pPeleRegs->isochTransmitA.channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO ();
-
- #ifdef PeleFireBug
- {
- UInt32 temp = EndianSwap32Bit (pPeleRegs->fifoOverUnderErrorCounters);
- sprintf (fireBug, "PeleFWIM: FIFO stats during iso tx: ITF_UNDER %ld, ATF_UNDER %ld, GRF_OVER %ld",
- (temp >> 16) & 0xff, (temp >> 8) & 0xff, temp & 0xff);
- PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
- }
- #endif
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMStopListeningDCLProgram
- //
- // This routine stops running the given DCL program.
- //
-
- static OSStatus PeleFWIMStopListeningDCLProgram(
- DCLProgramID dclProgramID)
- {
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMStopListeningDCLProgram");
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
- if (status == noErr)
- pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
-
- // Get base address of Pele registers.
- if (status == noErr)
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Stop the DMA engine.
- if (status == noErr)
- {
- // Stop the DMA - zzz could be more graceful, not stop mid-packet.
- //zzz need way to bit bucket any remaining packets in FIFO
-
- pPeleRegs->isochReceiveA.channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO ();
-
- pPeleRegs->isochReceiveB.channelControl = EndianSwapImm32Bit (kPeleClrAll);
- SynchronizeIO ();
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMReleaseDCLProgram
- //
- // This routine releases the resources allocated for the given DCL program.
- //
-
- static OSStatus PeleFWIMReleaseDCLProgram(
- DCLProgramID dclProgramID)
- {
- PeleDCLCompilerEngineDataPtr
- pPeleDCLCompilerEngineData;
- PeleFWIMDataPtr pPeleFWIMData;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\p PeleFWIMReleaseDCLProgram");
-
- // Get our engine data and FWIM data.
- status = FWGetDCLProgramEngineData
- (dclProgramID, (UInt32 *) &pPeleDCLCompilerEngineData);
- if (status == noErr)
- pPeleFWIMData = pPeleDCLCompilerEngineData->pPeleFWIMData;
-
- if (status == noErr)
- {
- // Deallocate PCL pools.
- if (pPeleDCLCompilerEngineData->pPeleDMAPoolDataList != nil)
- {
- PeleFWIMDeallocateDMAPools
- (pPeleDCLCompilerEngineData->pPeleDMAPoolDataList);
- }
-
- // Release all VM resources
- // Kind of a hack - we set this to -1 if the PrepareMemoryForIO failed:
- if (pPeleDCLCompilerEngineData->ioPrep.mappingEntryCount != -1)
- {
- status = CheckpointIO (pPeleDCLCompilerEngineData->ioPrep.preparationID, kNilOptions);
- if (status != noErr)
- {
- sprintf (debugStr, "DCL data CheckpointIO status %ld",
- (long) status);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- }
- PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData->ioPrep.rangeInfo.multipleRanges.rangeTable);
- PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData->ioPrep.physicalMapping);
- }
-
- // Deallocate compiler data list for DCLs
- if (pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData != nil)
- PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData->pPeleDCLCompilerDCLData);
-
- // Deallocate engine data.
- PoolDeallocate ((Ptr) pPeleDCLCompilerEngineData);
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMReadRequestTimeoutHandler
- //
- // This proc will retry a transaction if any more retries are specified.
- //
-
- static OSStatus PeleFWIMReadRequestTimeoutHandler(
- void *p1,
- void *p2)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) p1;
- PeleFWIMDataPtr pPeleFWIMData;
- UInt32 commandAcceptance;
- Boolean commandBusy;
- OSStatus pendingFWIMCommandStatus,
- status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMReadRequestTimeoutHandler");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pendingFWIMCommandStatus = pPeleFWIMData->pendingFWIMCommandStatus;
-
- // Note that timer went off.
- pPeleFWIMData->requestTimeoutTimerSet = false;
-
- // Check if command is still busy.
- if (pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
- {
- commandBusy = true;
- }
- else
- {
- commandBusy = false;
- status = pendingFWIMCommandStatus;
- }
-
- // Retry if there are more retries left, otherwise return with timeout
- // status.
- if (commandBusy)
- {
- if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
- {
- status = PeleFWIMRead (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
- }
- else
- {
- status = timeoutErr;
- }
-
- if (status != noErr)
- commandBusy = false;
- }
-
- // Complete command if it's no longer busy.
- if (!commandBusy)
- {
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMWriteRequestTimeoutHandler
- //
- // This proc will retry a transaction if any more retries are specified.
- //zzz Only need this until reset code completes commands manually.
- //zzz need locking mechanism between this routine and the ack int routine.
- //
- // Note - presently unused (not set in PeleFWIMWrite)
-
- static OSStatus PeleFWIMWriteRequestTimeoutHandler(
- void *p1,
- void *p2)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) p1;
- PeleFWIMDataPtr pPeleFWIMData;
- PeleRegistersPtr pPeleRegs;
- Boolean commandBusy;
- OSStatus pendingFWIMCommandStatus,
- status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMWriteRequestTimeoutHandler");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pendingFWIMCommandStatus = pPeleFWIMData->pendingFWIMCommandStatus;
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- // Note that timer went off.
- pPeleFWIMData->requestTimeoutTimerSet = false;
-
- // Check if command is still busy.
- if (pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
- {
- commandBusy = true;
- }
- else
- {
- commandBusy = false;
- status = pendingFWIMCommandStatus;
- }
-
- // Check if ack code indicates a completed transfer. Retry if it doesn't.
- if (commandBusy)
- {
- // NYI
- // Works differently in Pele - look in DMA/PCL status
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMWriteRequestTimeoutHandler - NYI ###");
- #if 0
- nodeAddress = EndianSwap32Bit (pLinkRegs->nodeAddress);
- ackCode =
- (nodeAddress & kTINodeAddressATAck) >> kTINodeAddressATAckPhase;
- if (ackCode == kFWAckComplete)
- {
- commandBusy = false;
- status = noErr;
- }
- else
- {
- if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
- {
- status = PeleFWIMWrite (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
- }
- else
- {
- status = timeoutErr;
- }
-
- if (status != noErr)
- commandBusy = false;
- }
- #endif
- }
-
- // Complete command if it's no longer busy.
- if (!commandBusy)
- {
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status =
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMLockRequestTimeoutHandler
- //
- // This proc will retry a transaction if any more retries are specified.
- //zzz need to check if command is still busy.
- // NYI - Never tested for Pele
- //
-
- static OSStatus PeleFWIMLockRequestTimeoutHandler(
- void *p1,
- void *p2)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) p1;
- PeleFWIMDataPtr pPeleFWIMData;
- UInt32 commandAcceptance;
- Boolean commandBusy;
- OSStatus pendingFWIMCommandStatus,
- status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMLockRequestTimeoutHandler");
-
- // Get our internal data.
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
- pPeleFWIMData = (PeleFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
- pendingFWIMCommandStatus = pPeleFWIMData->pendingFWIMCommandStatus;
-
- // Note that timer went off.
- pPeleFWIMData->requestTimeoutTimerSet = false;
-
- // Check if command is still busy.
- if (pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
- {
- commandBusy = true;
- }
- else
- {
- commandBusy = false;
- status = pendingFWIMCommandStatus;
- }
-
- // Retry if there are more retries left, otherwise return with timeout
- // status.
- if (commandBusy)
- {
- if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
- {
- status = PeleFWIMLock (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
- }
- else
- {
- status = timeoutErr;
- }
-
- if (status != noErr)
- commandBusy = false;
- }
-
- // Complete command if it's no longer busy.
- if (!commandBusy)
- {
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status =
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDMAARDeferredTask
- //
- // Dispatches self-ID and asynch packets after DMA is finished
- //
-
- static void PeleFWIMDMAARDeferredTask(
- void *p1,
- void *p2)
- {
- PeleFWIMDataPtr pPeleFWIMData = (PeleFWIMDataPtr) p1;
- PeleDMAPtr pDMA;//, pSkimDMA;
- PeleAsynchRxDMADataPtr pRxDMAData;//, pLastSelfIDsRxDMAData, pSkimRxDMAData;
- UInt32 dmaResult;//, skimStatus;
- UInt32 packetSize;//, skimSize;
- Ptr packetBuffer;
- UInt32 packetStatus, ackSent;
- // UInt32 quad0, quad1;
- // Boolean skimDone;
- // UInt32 skipCount;
- // static UInt32 skipTotal = 0;
- OSStatus status = noErr;
-
- // Asynch receive DT no longer scheduled.
- pPeleFWIMData->asynchReceiveDTScheduled = false;
-
- // This is part of a temporary hack.
- // Within 50ms after a bus reset, don't accept any packets.
- // We'll get called again after these flags are cleared.
-
- if ((pPeleFWIMData->delayedResetTimerSet) || (pPeleFWIMData->busResetDTScheduled))
- return;
-
- // Get next descriptor to process and its data.
- pRxDMAData = pPeleFWIMData->pNextAsynchRxDMAData;
- if (pRxDMAData != nil)
- {
- pDMA = pRxDMAData->pDMA;
- dmaResult = EndianSwap32Bit (pDMA->result);
- }
- else
- {
- dmaResult = 0;
- }
-
- // Process all descriptors with data.
- while (dmaResult & kPeleXferStatusActive)
- {
- // Set next PCL to process.
- pPeleFWIMData->pNextAsynchRxDMAData = pRxDMAData->pNextRxDMAData;
-
- // If this packet is self-IDs, and we are running behind, then
- // there could be *another* packet with self-IDs waiting too.
- // In that case, we can avoid a bunch of PHY register reads
- // and other work by just skipping to the last available self-IDs.
- // The skipped packets can't contain any responses we want, and
- // we will be unable to reply to any requests during that period,
- // so we can safely dispose of all of the packets.
-
- // In theory it is possible for someone to have sent us a write
- // request to which we sent ack_complete. However, because this
- // write request was sent after a bus reset, and before we had ever
- // identified ourselves, the sender has no way to know who we are.
- // So we can safely ignore such a request even if we said ack_complete.
-
- // zzz However, if someone sent a *broadcast* write, they might reasonably
- // except us to (try to) receive it. If we find a broadcast write while
- // scanning ahead, we really ought to stop scanning at that point.
-
- packetBuffer = pRxDMAData->packetBuffer;
- packetSize = kAsyncRxPacketBufferSize - (dmaResult & kPeleResCountMask);
- packetStatus = *((UInt32 *) (packetBuffer + packetSize - 4));
- ackSent = packetStatus & kPelePacketAckSent;
-
- // If we really sent an ack, then process the packet only if we didn't
- // complain (ackDataErr, etc.) In cases where we didn't send an ack,
- // this value will be ackComplete if Pele found nothing wrong.
- // If anything went wrong, just recycle the buffer and descriptor.
-
- if ((ackSent == kFWAckComplete) || (ackSent == kFWAckPending))
- {
- #if 0
- zzz
- // Get first two quads.
- quad0 = ((UInt32 *) packetBuffer)[0];
- quad1 = ((UInt32 *) packetBuffer)[1];
-
- // If length is zero or first quad is inverse of second quad, assume self-IDs
- if ((packetSize == 0) || (quad0 == ~quad1))
- {
- // Self-IDs
- pLastSelfIDsPCL = pSkimPCL = pPCL;
- pSkimPCLData = (PeleAsynchRxDMADataPtr) pSkimPCL->refCon;
- skimStatus = EndianSwap32Bit (pPCL->status);
- skimDone = false;
-
- while (skimDone == false)
- {
- // Move to next PCL
- pSkimPCL = pSkimPCLData->pNextPCL;
- if (pSkimPCL == nil)
- {
- // Hit the end of the list
- skimDone = true;
- }
- else
- {
- pSkimPCLData = (PeleAsynchRxDMADataPtr) pSkimPCL->refCon;
- skimStatus = EndianSwap32Bit (pSkimPCL->status);
- }
-
- if ((skimDone == false) && (skimStatus & kPelePktCmp))
- {
- // pSkimPCL points to a PCL that has been executed
- // If this one had an error, just keep looking.
- if (!(skimStatus & (kPeleMstErr | kPelePktErr)))
- {
- // Get packet buffer and length.
- skimSize = (skimStatus & kPeleTransferredCount) >>
- kPeleTransferredCountPhase;
-
- // Get first two quads.
- quad0 = ((UInt32 *) pSkimPCLData->packetBuffer)[0];
- quad1 = ((UInt32 *) pSkimPCLData->packetBuffer)[1];
-
- // If length is zero or first quad is inverse of second quad, assume self-IDs
- if ((skimSize == 0) || (quad0 == ~quad1))
- {
- // This is the latest point we can skip ahead to (so far)
- pLastSelfIDsPCL = pSkimPCL;
- }
- }
- }
- else // ran out of places to look
- {
- skimDone = true;
- }
- }
-
- if (pLastSelfIDsPCL != pPCL)
- {
- // recycle skipped PCLs and
- // set up for alternate
-
- skipCount = 0;
- while (pPCL != pLastSelfIDsPCL)
- {
- // Add PCL back to active list.
- pSkimPCLData = (PeleAsynchRxDMADataPtr) pPCL->refCon;
- pSkimPCL = pSkimPCLData->pNextPCL;
- PeleFWIMAddAsynchRxDMA (pPCL);
- pPCL = pSkimPCL;
- skipCount++;
- skipTotal++;
- }
-
- pPeleAsynchRxDMAData = (PeleAsynchRxDMADataPtr) pPCL->refCon;
- pPeleFWIMData->pNextAsynchRxDMAData = pPeleAsynchRxDMAData->pNextPCL;
- pclStatus = EndianSwap32Bit (pPCL->status);
- packetBuffer = pPeleAsynchRxDMAData->packetBuffer;
- packetSize = (pclStatus & kPeleTransferredCount) >>
- kPeleTransferredCountPhase;
-
- //sprintf (fireBug, "PeleFWIM: Skipped %ld useless packets [%ld total]",
- // (long) skipCount, (long) skipTotal);
- //PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
- }
- }
- #endif
- // Process packet.
- PeleFWIMProcessPacket (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- }
- else
- {
- // Add back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
- // Process next descriptor, if it's ready.
- pRxDMAData = pPeleFWIMData->pNextAsynchRxDMAData;
- if (pRxDMAData != nil)
- {
- pDMA = pRxDMAData->pDMA;
- dmaResult = EndianSwap32Bit (pDMA->result);
- }
- else
- {
- dmaResult = 0;
- }
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDMAIsochReceiveDeferredTask
- //
- // Handles DMA interrupts for isochronous receive.
- //
-
- static void PeleFWIMDMAIsochReceiveDeferredTask(
- void *p1,
- void *p2)
- {
- PeleFWIMDataPtr pPeleFWIMData = (PeleFWIMDataPtr) p1;
- PeleIsochPortDataPtr pPeleIsochPortData;
- static DCLCommandPtr pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
- DCLCommandPtr pDCLInterrupt,
- pPrevDCLInterrupt;
- DCLCommandPtr pDCLCommand;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- DCLCallProcPtr pDCLCallProc;
- DCLUpdateDCLListPtr pDCLUpdateDCLList;
- UInt32 numInterrupts;
- OSStatus status = noErr;
-
- FWDebugStr ((ConstStr255Param) "\pPeleFWIMIsochReceiveDeferredTask");
-
- // Isoch receive DT no longer scheduled.
- pPeleFWIMData->isochReceiveDTScheduled = false;
-
- // Get isoch port data.
- pPeleIsochPortData = pPeleFWIMData->lynxIsochPortDataList[kIsochReceiveDMA];
-
- // Get and clear interrupt queue tail.
- pDCLInterrupt = pPeleFWIMData->pDCLInterruptTail[kIsochReceiveDMA];
- while (!CompareAndSwap
- ((UInt32) pDCLInterrupt,
- nil,
- (UInt32 *) &(pPeleFWIMData->pDCLInterruptTail[kIsochReceiveDMA])))
- {
- pDCLInterrupt = pPeleFWIMData->pDCLInterruptTail[kIsochReceiveDMA];
- }
-
-
- // Build interrupt list and clear interrupts.
- numInterrupts = 0;
-
- // I thought this was increased to 100 - bug in LynxFWIM sample code too?
-
- while ((pDCLInterrupt != nil) && (numInterrupts < 10))
- {
- // Value we get back from STORE_QUAD has been endian-swapped:
- //zzz could we fix that when writing the program?!
-
- pDCLInterrupt = (DCLCommandPtr) EndianSwap32Bit ((UInt32) pDCLInterrupt);
-
- pDCLInterruptList[numInterrupts] = pDCLInterrupt;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLInterrupt->compilerData;
- pPrevDCLInterrupt = (DCLCommandPtr) pPeleDCLCompilerDCLData->pDMA->cmdDep;
- pPeleDCLCompilerDCLData->pDMA->cmdDep = nil;
- numInterrupts++;
-
- pDCLInterrupt = pPrevDCLInterrupt;
- }
-
- // Run through interrupt queue.
- while (numInterrupts--)
- {
- // Get DCL command that caused interrupt.
- pDCLCommand = pDCLInterruptList[numInterrupts];
-
- //zzz
- // pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLCommand->compilerData;
- // sprintf (debugStr, "Interrupt DCL %08lx (DBDMA %08lx)",
- // (long) pDCLCommand,
- // (long) pPeleDCLCompilerDCLData->pDMA);
- // FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- //zzz
-
- // Dispatch off of opcode.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLCallProcOp :
- // Call the proc.
- pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
- FWCallDCLCallProc (pPeleIsochPortData->dclProgramID, pDCLCallProc);
- break;
-
- case kDCLUpdateDCLListOp :
- // Update the DCL list.
- pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
- PeleFWIMDCLCompilerUpdateNotification (pPeleIsochPortData->dclProgramID,
- pDCLUpdateDCLList->dclCommandList,
- pDCLUpdateDCLList->numDCLCommands);
- break;
-
- default :
- break;
- }
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMDMAIsochTransmitDeferredTask
- //
- // Handles DMA interrupts for isochronous transmit.
- //
-
- static void PeleFWIMDMAIsochTransmitDeferredTask(
- void *p1,
- void *p2)
- {
- PeleFWIMDataPtr pPeleFWIMData = (PeleFWIMDataPtr) p1;
- PeleIsochPortDataPtr pPeleIsochPortData;
- static DCLCommandPtr pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
- DCLCommandPtr pDCLInterrupt,
- pPrevDCLInterrupt;
- PeleDCLCompilerDCLDataPtr pPeleDCLCompilerDCLData;
- DCLCommandPtr pDCLCommand;
- DCLCallProcPtr pDCLCallProc;
- DCLUpdateDCLListPtr pDCLUpdateDCLList;
- UInt32 numInterrupts;
- OSStatus status = noErr;
-
- // Isoch transmit DT no longer scheduled.
- pPeleFWIMData->isochTransmitDTScheduled = false;
-
- // Get isoch port data.
- pPeleIsochPortData = pPeleFWIMData->lynxIsochPortDataList[kIsochTransmitDMA];
-
- // Get and clear interrupt queue tail.
- pDCLInterrupt = pPeleFWIMData->pDCLInterruptTail[kIsochTransmitDMA];
- while (!CompareAndSwap
- ((UInt32) pDCLInterrupt,
- nil,
- (UInt32 *) &(pPeleFWIMData->pDCLInterruptTail[kIsochTransmitDMA])))
- {
- pDCLInterrupt = pPeleFWIMData->pDCLInterruptTail[kIsochTransmitDMA];
- }
-
- // Build interrupt list and clear interrupts.
- numInterrupts = 0;
- while ((pDCLInterrupt != nil) && (numInterrupts < 10))
- {
- // Value we get back from STORE_QUAD has been endian-swapped:
- //zzz could we fix that when writing the program?!
-
- pDCLInterrupt = (DCLCommandPtr) EndianSwap32Bit ((UInt32) pDCLInterrupt);
-
- pDCLInterruptList[numInterrupts] = pDCLInterrupt;
- pPeleDCLCompilerDCLData = (PeleDCLCompilerDCLDataPtr) pDCLInterrupt->compilerData;
- pPrevDCLInterrupt = (DCLCommandPtr) pPeleDCLCompilerDCLData->pDMA->cmdDep;
- pPeleDCLCompilerDCLData->pDMA->cmdDep = nil;
- numInterrupts++;
-
- pDCLInterrupt = pPrevDCLInterrupt;
- }
-
- // Run through interrupt queue.
- while (numInterrupts--)
- {
- // Get DCL command that caused interrupt.
- pDCLCommand = pDCLInterruptList[numInterrupts];
-
- // Dispatch off of opcode.
- switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
- {
- case kDCLCallProcOp :
- // Call the proc.
- pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
- FWCallDCLCallProc (pPeleIsochPortData->dclProgramID, pDCLCallProc);
- break;
-
- case kDCLUpdateDCLListOp :
- // Update the DCL list.
- pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
- PeleFWIMDCLCompilerUpdateNotification (pPeleIsochPortData->dclProgramID,
- pDCLUpdateDCLList->dclCommandList,
- pDCLUpdateDCLList->numDCLCommands);
- break;
-
- default :
- break;
- }
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMResetDeferredTask
- //
- // This proc deals with bus resets at FireWire deferred task time.
- //
-
- static void PeleFWIMResetDeferredTask(
- void *p1,
- void *p2)
- {
- PeleFWIMDataPtr pPeleFWIMData = (PeleFWIMDataPtr) p1;
- AbsoluteTime timeoutAbsolute;
- OSStatus status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMResetDeferredTask");
-
- // Bus reset DT no longer scheduled.
- pPeleFWIMData->busResetDTScheduled = false;
-
- // This is a temporary hack. We want to reduce the risk of PHY jams.
- // So after a bus reset, before we process the self-IDs, wait 50ms to
- // allow another bus reset (if any) to arrive. When this timer goes
- // off, if busResetDTScheduled has become true again, then there was
- // another bus reset. By the time we get to the self-IDs for the first
- // reset, we'll be able to skip forward over them and avoid some PHY
- // register accesses.
-
- // If there are more resets beyond 50ms, we won't keep waiting - otherwise
- // we might hang if there were endless resets. But hopefully we will have
- // managed to skip some of them.
-
- if (pPeleFWIMData->delayedResetTimerSet == false)
- {
- timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (50 * durationMillisecond));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- PeleFWIMDelayedReset,
- pPeleFWIMData,
- &(pPeleFWIMData->delayedResetTimerID));
- if (status == noErr)
- pPeleFWIMData->delayedResetTimerSet = true;
- else PeleFWIMDelayedReset (p1, nil); // Might as well proceed (should never happen)
- }
- }
-
-
- static OSStatus PeleFWIMDelayedReset(
- void *p1,
- void *p2)
- {
- PeleFWIMDataPtr pPeleFWIMData = (PeleFWIMDataPtr) p1;
-
- pPeleFWIMData->delayedResetTimerSet = false;
-
- // If there's a pending FWIM command, set its status to busReconfiguredErr.
- //zzz should we do this here, or in services?
- //zzz this probably should not be done on all types of commands.
- if (pPeleFWIMData->pPendingFWIMCommand)
- {
- if (pPeleFWIMData->pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
- pPeleFWIMData->pendingFWIMCommandStatus = busReconfiguredErr;
- }
-
- // During the period that delayedResetTimerSet was true,
- // no asynch packets were processed.
- // Now (another hack) process any that are waiting:
-
- PeleFWIMHandleDMAARInterrupt (pPeleFWIMData);
-
- return noErr;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMMiscInterruptDeferredTask
- //
- // This proc deals with miscellaneous interrupts at FireWire deferred task time.
- //
-
- static void PeleFWIMMiscInterruptDeferredTask(
- void *p1,
- void *p2)
- {
- PeleFWIMDataPtr pPeleFWIMData = (PeleFWIMDataPtr) p1;
- UInt32 i;
-
- // DT no longer scheduled.
- pPeleFWIMData->miscInterruptDTScheduled = false;
-
- i = pPeleFWIMData->miscInterrupt;
- pPeleFWIMData->miscInterrupt = 0;
-
- #ifdef PeleFireBug
- sprintf (fireBug, "PeleFWIM: Interrupts: %s%s%s%s%s%s%s%s%s%s",
- (i & kPelePHY_TIME_OUT) ? "PHY_TO " : "",
- (i & kPeleIT_STUCK) ? "IT_STUCK " : "",
- (i & kPeleAT_STUCK) ? "AT_STUCK " : "",
- (i & kPeleHDR_ERR) ? "CRC_ERR " : "",
- (i & kPeleTC_ERR) ? "TC_ERR " : "",
- (i & kPeleCYC_LOST) ? "CYC_LOST " : "",
- (i & kPeleCYC_ARB_FAILED) ? "CYC_ARB " : "",
- (i & kPeleITF_UNDER_FLOW) ? "ITF_UF " : "",
- (i & kPeleATF_UNDER_FLOW) ? "ATF_UF " : "",
- (i & kPeleIARB_FAILED) ? "IARB " : "");
- //if (i) PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
- #endif
-
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMAckSecondaryInterruptHandler
- //
- // This proc checks the ack received for the sent transaction. If the ack
- // specifies a completed transaction, this proc will complete the transaction.
- // If the ack specifies an error, this proc will retry the transaction.
- //zzz need to handle response pending ack.
- //zzz need locking mechanism between this routine and the timeout routine
- //
- // We aren't called by interrupt, we're called directly by PeleFWIMWrite()
-
- static OSStatus PeleFWIMAckSecondaryInterruptHandler(
- void *p1,
- void *p2)
- {
- FWIMCommandParamsPtr pFWIMCommandParams;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- PeleFWIMDataPtr pPeleFWIMData = (PeleFWIMDataPtr) p1;
- PeleDMAPtr pPCL = (PeleDMAPtr) p2;
- AbsoluteTime timeoutAbsolute;
- UInt32 ackCode, ackType, tryAgain;
- Boolean commandBusy;
- OSStatus pendingFWIMCommandStatus,
- status = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMAckSecondaryInterruptHandler");
-
- // Get our internal data.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
- pendingFWIMCommandStatus = pPeleFWIMData->pendingFWIMCommandStatus;
- pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
-
- // Make sure pending command is a write.
- if (pFWIMCommandParams->commandType == kFWIMWrite)
- {
- if (status == noErr)
- {
- // Check if command is still busy.
- if (pendingFWIMCommandStatus == kPelePendingFWIMCommandBusy)
- {
- commandBusy = true;
- }
- else
- {
- commandBusy = false;
- status = pendingFWIMCommandStatus;
- }
-
- // Check if ack code indicates a completed transfer. Retry if it doesn't.
- if (commandBusy)
- {
- //zzz fake ack complete
- ackCode = 1;
- ackType = 0;
-
- // This is where to look for the real ack:
- // pPeleFWIMData->asynchTxDoneDMASegment->pDMA->result
-
- // ackCode = (EndianSwap32Bit (pPCL->status) & kPeleAcks) >> kPeleAcksPhase;
- // ackType = ((EndianSwap32Bit (pPCL->status) & kPeleAck_Type) != 0);
- tryAgain = 0;
-
- if (ackType == 0) // Normal 1394 ack
- {
- if ((ackCode == kFWAckComplete) || (ackCode == kFWAckPending))
- {
- // This happens the majority of the time.
- //zzz should wait for write response when ack pending
- commandBusy = false;
- }
- else if (ackCode != kFWAckTypeError)
- {
- // This should only be AckDataError, meaning the packet we sent
- // failed CRC at the receiver. However, non-revA parts seem to
- // yield ack 0 in this case. So except for TypeError, just try
- // again. TypeError will probably fail again if we try again,
- // so give up in that case.
- tryAgain = 1;
- }
- else // TypeError
- {
- commandBusy = false;
- status = retryExceededErr; //zzz do we have a better error code?
- }
- }
- else // Some Pele error code, not a real ack
- {
- if ((ackCode == 0) || (ackCode == 1))
- {
- // 0 indicates retry overrun (too many retries)
- // 1 indicates Link Timeout - meaning nobody home. Assume no Link at that Phy.
- status = retryExceededErr;
- commandBusy = false;
- }
- else if (ackCode == 2)
- {
- // 2 indicates FIFO underrun. This happens sometimes.
- // Just try again.
- // zzz should only retry a limited number of times.
- tryAgain = 1;
- }
- }
- }
-
- if (tryAgain)
- {
- timeoutAbsolute =
- AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (10 * durationMillisecond));
- status = SetInterruptTimer
- (&timeoutAbsolute,
- PeleFWIMWriteTimer,
- pFWIMAsynchCommandParams,
- &(pPeleFWIMData->requestTimeoutTimerID));
- if (status == noErr)
- pPeleFWIMData->requestTimeoutTimerSet = true;
-
- if (status != noErr)
- commandBusy = false;
- }
-
- // Complete command if it's no longer busy.
- if (!commandBusy)
- {
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status =
- FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID,
- status);
- }
- }
- }
-
- return status;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessPacket
- //
- // Dispatch packet processing based on tCode (asynch or isoch).
- //zzz check destID???
- //
-
- static void PeleFWIMProcessPacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 tCode;
- UInt32 quad0;
-
- // Get first two quads.
- quad0 = ((UInt32 *) packetBuffer)[0];
-
- tCode = (quad0 & kPelePacketTCode) >> kPelePacketTCodePhase;
-
- #if 0
- zzz check ack sent if not self-id - its in the packet trailer
- if (tCode != kPeleTCodeSelfID)
- {
- pclStatus = EndianSwap32Bit (pPCL->status);
- ackCode = (pclStatus & kPeleAcks) >> kPeleAcksPhase;
- if ((ackCode != 1) && (ackCode != 2))
- {
- tCode = 0x0f; // reserved
-
- //sprintf (fireBug, "PeleFWIM: Whoops, ack %ld in received packet [%08lx]",
- // (long) ackCode, (long) pclStatus);
- //PeleFWIMFireBugMsg (pPeleFWIMData, fireBug);
- }
- }
- #endif
-
- // Dispatch processing based on tCode.
- switch (tCode)
- {
- case kFWTCodeWriteQuadlet :
- PeleFWIMProcessWriteQuadletPacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kFWTCodeWriteBlock :
- PeleFWIMProcessWriteBlockPacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kFWTCodeWriteResponse :
- PeleFWIMProcessWriteResponsePacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kFWTCodeReadQuadlet :
- PeleFWIMProcessReadQuadletPacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kFWTCodeReadBlock :
- PeleFWIMProcessReadBlockPacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kFWTCodeReadQuadletResponse :
- PeleFWIMProcessReadQuadletResponsePacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kFWTCodeReadBlockResponse :
- PeleFWIMProcessReadBlockResponsePacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kFWTCodeLock :
- PeleFWIMProcessLockPacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kFWTCodeLockResponse :
- PeleFWIMProcessLockResponsePacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- case kPeleTCodeSelfID :
- PeleFWIMProcessSelfIDPacket
- (pPeleFWIMData, pRxDMAData, packetBuffer, packetSize);
- break;
-
- default :
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- break;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessSelfIDPacket
- //
- // This proc tries to process a selfID packet.
- //zzz Should validate selfIDs by making sure the phyID is correct , there's
- //zzz enough of them, etc. Need to generate CRC. Should cancel timeout timer.
- //
-
- static void PeleFWIMProcessSelfIDPacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- PeleRegistersPtr pPeleRegs;
- FWIMProcessSelfIDsParams fwimProcessSelfIDsParams;
- UInt32 localSelfIDQuads[2];
- UInt32 *pSelfIDPackets = (UInt32 *) packetBuffer;
- UInt32 localSelfID;
- UInt32 physicalID;
- UInt32 gapCount;
- UInt32 speed;
- UInt32 contender;
- UInt32 portStatus;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessSelfIDPacket");
-
- if ((packetSize == 8) && ((pSelfIDPackets[1] & 0xFFFFFFF0) != 0))
- {
- // packetSize == 8, must be empty-bus selfIDs or a PHY packet.
- // If anything other than the ack is in the second quadlet, it's PHY:
-
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- return;
- }
-
- pPeleRegs = pPeleFWIMData->pPeleRegisters;
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // Build our local selfID.
- //
-
- //zzz check for ack_complete in packet trailer to indicate OK reception.
-
- // Get physical ID and root bit.
- physicalID = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyPhysicalIDAddress);
- if (physicalID & kPelePhyR)
- pPeleFWIMData->root = true;
- else
- pPeleFWIMData->root = false;
- physicalID = (physicalID & kPelePhyPhysicalID) >> kPelePhyPhysicalIDPhase;
- localSelfID = physicalID << kFWSelfIDPhyIDPhase;
-
- // This will have already been done by the PhyReg primary interrupt handler.
- // But do it again here just to be safe (there is a possible race condition)
-
- // Disable cycle mastering if we're not root.
- if (!pPeleFWIMData->root)
- {
- pPeleRegs->control &= ~EndianSwapImm32Bit (kPeleControlCycleMaster);
- SynchronizeIO ();
- }
-
- // Get gap count.
- gapCount = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyGCAddress);
- gapCount = (gapCount & kPelePhyGC) >> kPelePhyGCPhase;
- localSelfID |= gapCount << kFWSelfID0GapCntPhase;
-
- // Get speed.
- speed = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhySPDAddress);
- speed = (speed & kPelePhySPD) >> kPelePhySPDPhase;
- localSelfID |= speed << kFWSelfID0SPPhase;
-
- // Get contender bit.
- //zzz assume hardwired to 1
- contender = 1;
- if (contender & 1)
- localSelfID |= kFWSelfID0C;
- /*zzz should do it like this. */
- #if 0
- contender = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyCAddress);
- if (contender & kPelePhyC)
- localSelfID |= kFWSelfID0C;
- #endif
-
- // Get port status p0.
- portStatus = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyPortStatus1Address);
- if (portStatus & kPelePhyCon1)
- {
- if (portStatus & kPelePhyCh1)
- localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P0Phase;
- else
- localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P0Phase;
- }
- else
- {
- localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P0Phase;
- }
-
- // Get port status p1.
- portStatus = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyPortStatus2Address);
- if (portStatus & kPelePhyCon2)
- {
- if (portStatus & kPelePhyCh2)
- localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P1Phase;
- else
- localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P1Phase;
- }
- else
- {
- localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P1Phase;
- }
-
- // Get port status p2.
- portStatus = PeleFWIMReadPhyRegister (pPeleFWIMData, pPeleRegs, kPelePhyPortStatus3Address);
- if (portStatus & kPelePhyCon3)
- {
- if (portStatus & kPelePhyCh3)
- localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P2Phase;
- else
- localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P2Phase;
- }
- else
- {
- localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P2Phase;
- }
-
- // Set selfID packet ID, link active, self powered and
- // provides 15W.
- //zzz 15W is just a guess. Need to determine real number.
- localSelfID |= ((kFWSelfIDPacketID << kFWPhyPacketIDPhase) |
- kFWSelfID0L |
- (kFWSelfIDSelfPowered15W << kFWSelfID0PwrPhase));
-
- // Process the self IDs.
- //zzz need to get status.
- localSelfIDQuads[0] = localSelfID;
- localSelfIDQuads[1] = ~localSelfID;
- fwimProcessSelfIDsParams.fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
- fwimProcessSelfIDsParams.pSelfIDList = ((Ptr) pSelfIDPackets) + 4;
- fwimProcessSelfIDsParams.selfIDListSize = packetSize - 8;
- fwimProcessSelfIDsParams.pLocalSelfID = (Ptr) localSelfIDQuads;
- fwimProcessSelfIDsParams.localSelfIDSize = 8;
- fwimProcessSelfIDsParams.processSelfIDsFlags = 0;
- FWProcessSelfIDs (&fwimProcessSelfIDsParams);
-
- pPeleFWIMData->generation = fwimProcessSelfIDsParams.generation;
- pPeleFWIMData->generationValid = true;
-
- // We used to load the nodeID register here, but this was a bad place to
- // do it. That's now done based on PHY register receive interrupts.
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessWriteQuadletPacket
- //
- // This proc processes a write quadlet packet.
- //
-
- static void PeleFWIMProcessWriteQuadletPacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 trailerQuad;
- UInt32 transactionStatus;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessWriteQuadletPacket");
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- PeleFWIMProcessWriteQuadletRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);
- pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 3 * sizeof (UInt32));
- pFWIMProcessAsynchParams->length = 4;
- pFWIMProcessAsynchParams->extendedTCode = 0;
-
- trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
- transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the write request.
- FWProcessWriteRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessWriteQuadletRequestCompletionProc
- //
- // This proc will be called upon completion of write request processing.
- //
-
- static void PeleFWIMProcessWriteQuadletRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- PeleAsynchRxDMADataPtr pRxDMAData;
-
- // Get PCL pointer.
- pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessWriteBlockPacket
- //
- // This proc processes a write block packet.
- //
-
- static void PeleFWIMProcessWriteBlockPacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 trailerQuad;
- UInt32 transactionStatus;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessWriteBlockPacket");
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- PeleFWIMProcessWriteBlockRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);
- pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 4 * sizeof (UInt32));
-
- trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
- transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the write request.
- FWProcessWriteRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessWriteBlockRequestCompletionProc
- //
- // This proc will be called upon completion of write request processing.
- //
-
- static void PeleFWIMProcessWriteBlockRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- PeleAsynchRxDMADataPtr pRxDMAData;
-
- // Get PCL pointer.
- pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessWriteResponsePacket
- //
- // This proc processes a write quadlet response packet.
- //zzz Verify destinationID, and sourceID.
- //
- // NYI - never tested (never happens? same in TIFWIM)
-
- static void PeleFWIMProcessWriteResponsePacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- //zzz oops, Pele may need this.
- // Pele sends ack_pending to all writes that aren't handled by the physical unit.
- // so we're obligated to send write responses. But the LynxFWIM may not know what
- // to do with those - it may think the write failed because it only got pending.
- #if 0
- PeleRegistersPtr pPeleRegs;
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- UInt32 *pPacket;
- UInt32 commandType;
- UInt32 tLabel;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr;
- #endif
-
- // FWDebugStr ((ConstStr255Param) "\pNYI PeleFWIMProcessWriteResponsePacket");
- #if 0
- // Get pointer to link registers.
- pLinkRegs = (TILinkRegistersPtr) (pPeleFWIMData->regBaseAddress +
- kTILinkRegistersOffset);
-
- // Read in rest of packet.
- pPacket = (UInt32 *) packetBuffer;
- pPacket++;
- *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
- SynchronizeIO ();
- *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
- SynchronizeIO ();
- *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
- SynchronizeIO ();
- *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
- SynchronizeIO ();
-
- pPacket = (UInt32 *) packetBuffer;
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
-
- // We must have a pending write command and a matching transaction label.
- if (pFWIMAsynchCommandParams != nil)
- {
- // Get pending command type and transaction label for this packet.
- commandType =
- pFWIMAsynchCommandParams->fwimCommandParams.commandType;
- tLabel = (pPacket[0] & kPeleAsynchTLabel) >> kPeleAsynchTLabelPhase;
-
- if ((commandType == kFWIMWrite) &&
- (tLabel == pPeleFWIMData->transactionLabel) &&
- ((pPeleFWIMData->tCode == kFWTCodeWriteQuadlet) ||
- (pPeleFWIMData->tCode == kFWTCodeWriteBlock)))
- {
- // Try to cancel timeout timer.
- status = CancelTimer (pPeleFWIMData->requestTimeoutTimerID,
- &timeRemaining);
-
- // Complete command if we didn't time out.
- if (status == noErr)
- {
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
- noErr);
- }
- }
- }
- #endif
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessReadQuadletPacket
- //
- // This proc processes a read quadlet packet.
- //
-
- static void PeleFWIMProcessReadQuadletPacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 trailerQuad;
- UInt32 transactionStatus;
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- PeleFWIMProcessReadQuadletRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);//zzz should probably be nil.
- pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 3 * sizeof (UInt32));
- pFWIMProcessAsynchParams->length = 4;
- pFWIMProcessAsynchParams->extendedTCode = 0;
-
- trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
- transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the read request.
- FWProcessReadRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessReadQuadletRequestCompletionProc
- //
- // This proc will be called upon completion of read request processing.
- //
-
- static void PeleFWIMProcessReadQuadletRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- PeleAsynchRxDMADataPtr pRxDMAData;
-
- // Get PCL pointer.
- pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessReadBlockPacket
- //
- // This proc processes a read block packet.
- //
-
- static void PeleFWIMProcessReadBlockPacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 trailerQuad;
- UInt32 transactionStatus;
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- PeleFWIMProcessReadBlockRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz should probably be nil
- pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 4 * sizeof (UInt32));
-
- trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
- transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the read request.
- FWProcessReadRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessReadBlockRequestCompletionProc
- //
- // This proc will be called upon completion of read request processing.
- //
-
- static void PeleFWIMProcessReadBlockRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- PeleAsynchRxDMADataPtr pRxDMAData;
-
- // Get PCL pointer.
- pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessReadQuadletResponsePacket
- //
- // This proc processes a read quadlet response packet.
- //zzz Verify destinationID, and sourceID.
- //
-
- static void PeleFWIMProcessReadQuadletResponsePacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- UInt32 commandType;
- UInt32 tLabel;
- UInt32 rCode;
- UInt32 *commandBuffer;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr,
- responseStatus = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessReadQuadletResponsePacket");
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
-
- // We must have a pending read command and a matching transaction label.
- if (pFWIMAsynchCommandParams != nil)
- {
- // Get pending command type, transaction label, and response code for this packet.
- commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
- tLabel = (pPacket[0] & kPeleAsynchTLabel) >> kPeleAsynchTLabelPhase;
- rCode = (pPacket[1] & kPeleAsynchRCode) >> kPeleAsynchRCodePhase;
-
- if ((commandType == kFWIMRead) &&
- (tLabel == pPeleFWIMData->transactionLabel) &&
- (pPeleFWIMData->tCode == kFWTCodeReadQuadlet))
- {
- // Try to cancel timeout timer.
- status = CancelTimer (pPeleFWIMData->requestTimeoutTimerID,
- &timeRemaining);
-
- // Complete command if we didn't time out.
- if (status == noErr)
- {
- #if 0
- sprintf (debugStr, "QRead to %08lx %08lx returns %08lx [rcode %ld]",
- (long) pFWIMAsynchCommandParams->addressHi,
- (long) pFWIMAsynchCommandParams->addressLo,
- (long) pPacket[3],
- (long) rCode);
- FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
- #endif
-
- // Fill in command buffer.
- if (rCode == kFWResponseComplete)
- {
- commandBuffer = (UInt32 *) pFWIMAsynchCommandParams->buffer;
- *commandBuffer = pPacket[3];
- }
- else
- {
- responseStatus = accessErr;//zzz not always the best
- }
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
- responseStatus);
- }
- }
- }
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessReadBlockResponsePacket
- //
- // This proc processes a read block response packet.
- //zzz Verify destinationID, and sourceID.
- //zzz Must check extended tCode.
- //zzz Must return actual number of bytes transferred.
- //
- // NYI - never tested with Pele
-
- static void PeleFWIMProcessReadBlockResponsePacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- UInt32 commandType;
- UInt32 tLabel;
- UInt32 rCode;
- UInt32 dataLength;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr,
- responseStatus = noErr;
-
- //zzz should check ackSent to see if the packet was OK...?
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessReadBlockResponsePacket");
-
- dataLength = (((UInt32 *) packetBuffer)[3] & kPeleAsynchDataLength) >>
- kPeleAsynchDataLengthPhase;
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
-
- // We must have a pending read command and a matching transaction label.
- if (pFWIMAsynchCommandParams != nil)
- {
- // Get pending command type, transaction label, and response code for this packet.
- commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
- tLabel = (pPacket[0] & kPeleAsynchTLabel) >> kPeleAsynchTLabelPhase;
- rCode = (pPacket[1] & kPeleAsynchRCode) >> kPeleAsynchRCodePhase;
-
- if ((commandType == kFWIMRead) &&
- (tLabel == pPeleFWIMData->transactionLabel) &&
- (pPeleFWIMData->tCode == kFWTCodeReadBlock))
- {
- // Try to cancel timeout timer.
- status = CancelTimer (pPeleFWIMData->requestTimeoutTimerID,
- &timeRemaining);
-
- // Complete command if we didn't time out.
- if (status == noErr)
- {
- // Fill in command buffer.
- if (rCode == kFWResponseComplete)
- {
- if (dataLength > pFWIMAsynchCommandParams->length)
- dataLength = pFWIMAsynchCommandParams->length;
- BlockCopy (&(pPacket[4]),
- pFWIMAsynchCommandParams->buffer,
- dataLength);
- }
- else
- {
- responseStatus = accessErr;//zzz not always the best
- }
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
- responseStatus);
- }
- }
- }
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessLockPacket
- //
- // This proc processes a lock packet.
- //
-
- static void PeleFWIMProcessLockPacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- FWIMProcessAsynchParamsPtr pFWIMProcessAsynchParams;
- UInt32 trailerQuad;
- UInt32 transactionStatus;
-
- // Fill in processing params.
- pFWIMProcessAsynchParams = &(pRxDMAData->fwimProcessAsynchParams);
- pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pPeleFWIMData->fwimID;
- pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
- PeleFWIMProcessLockRequestCompletionProc;
- pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pRxDMAData;
- pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
- pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz receive and transmit buffers should be different
- pFWIMProcessAsynchParams->generation = pPeleFWIMData->generation;//zzz needs to be more accurate.
- BlockCopy (packetBuffer,
- &(pFWIMProcessAsynchParams->destinationID),
- 4 * sizeof (UInt32));
-
- trailerQuad = *((UInt32 *) (packetBuffer + packetSize - 4));
- transactionStatus = ((trailerQuad & kPelePacketAckSent) >> kPelePacketAckSentPhase) <<
- kFWTransactionStatusAckCodePhase;
- transactionStatus |= ((trailerQuad & kPelePacketSpd) >> kPelePacketSpdPhase) <<
- kFWTransactionStatusSpeedPhase;
- pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
-
- // Process the lock request.
- FWProcessLockRequest (pFWIMProcessAsynchParams);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessLockRequestCompletionProc
- //
- // This proc will be called upon completion of lock request processing.
- //
-
- static void PeleFWIMProcessLockRequestCompletionProc(
- FWIMProcessParamsPtr pFWIMProcessParams)
- {
- PeleAsynchRxDMADataPtr pRxDMAData;
-
- // Get PCL pointer.
- pRxDMAData = (PeleAsynchRxDMADataPtr) pFWIMProcessParams->completionProcData;
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // PeleFWIMProcessLockResponsePacket
- //
- // This proc processes a lock response packet.
- //zzz Verify destinationID, and sourceID.
- //zzz Must check extended tCode.
- //
- // (IRM sends these)
-
- static void PeleFWIMProcessLockResponsePacket(
- PeleFWIMDataPtr pPeleFWIMData,
- PeleAsynchRxDMADataPtr pRxDMAData,
- Ptr packetBuffer,
- UInt32 packetSize)
- {
- FWIMAsynchCommandParamsPtr pFWIMAsynchCommandParams;
- UInt32 *pPacket = (UInt32 *) packetBuffer;
- UInt32 commandType;
- UInt32 tLabel;
- UInt32 rCode;
- UInt32 dataLength;
- AbsoluteTime timeRemaining;
- OSStatus status = noErr,
- responseStatus = noErr;
-
- // FWDebugStr ((ConstStr255Param) "\pPeleFWIMProcessLockResponsePacket");
-
- dataLength = (pPacket[3] & kPeleAsynchDataLength) >> kPeleAsynchDataLengthPhase;
- if (dataLength & 0x03)
- dataLength = (dataLength & 0xFFFFFFFC) + 4;
-
- // Get the pending FWIM command if there is one.
- pFWIMAsynchCommandParams =
- (FWIMAsynchCommandParamsPtr) pPeleFWIMData->pPendingFWIMCommand;
-
- // We must have a pending lock command and a matching transaction label.
- if (pFWIMAsynchCommandParams != nil)
- {
- // Get pending command type, transaction label, and response code for this packet.
- commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
- tLabel = (pPacket[0] & kPeleAsynchTLabel) >> kPeleAsynchTLabelPhase;
- rCode = (pPacket[1] & kPeleAsynchRCode) >> kPeleAsynchRCodePhase;
-
- if ((commandType == kFWIMLock) &&
- (tLabel == pPeleFWIMData->transactionLabel) &&
- (pPeleFWIMData->tCode == kFWTCodeLock))
- {
- // Try to cancel timeout timer.
- status = CancelTimer (pPeleFWIMData->requestTimeoutTimerID,
- &timeRemaining);
-
- // Complete command if we didn't time out.
- if (status == noErr)
- {
- // Fill in command buffer.
- if (rCode == kFWResponseComplete)
- {
- if (dataLength > pFWIMAsynchCommandParams->length)
- dataLength = pFWIMAsynchCommandParams->length;
- BlockCopy (&(pPacket[4]),
- pFWIMAsynchCommandParams->buffer,
- dataLength);
- }
- else
- {
- responseStatus = accessErr;//zzz not always the best
- }
-
- // Finish up command.
- pPeleFWIMData->pPendingFWIMCommand = nil;
- status = FWIMCommandIsComplete
- (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
- responseStatus);
- }
- }
- }
-
- // Add PCL back to active list.
- PeleFWIMAddAsynchRxDMA (pRxDMAData);
- }
-
-
- static void PeleFWIMFireBugMsg (
- PeleFWIMDataPtr pPeleFWIMData,
- char *msg)
- {
- UInt32 sourceID;
-
- sourceID = EndianSwap32Bit (pPeleFWIMData->pPeleRegisters->nodeID << 16);
-
- PeleFWIMWriteAT (pPeleFWIMData, kFWSpeed100MBit, 4,
- 0x42420010, sourceID, 0x0, (strlen (msg) + 1) << 16,
- strlen (msg) + 1, (UInt32 *) msg);
- }
-
-
- /////////////////////////
- // End of PeleFWIM.c //
- /////////////////////////